How Shaders Can Shrink, Beautify, and Speed Up Your Web Pages – A WebGL Tutorial

This article explains how programmable shaders running on the GPU form the foundation of modern graphics rendering, and demonstrates step‑by‑step how to replace a large transparent PNG background, create animated particle effects, and draw complex patterns directly with GLSL in WebGL, resulting in smaller, more dynamic, and faster web pages.

Taobao Frontend Technology
Taobao Frontend Technology
Taobao Frontend Technology
How Shaders Can Shrink, Beautify, and Speed Up Your Web Pages – A WebGL Tutorial

Programmable Shaders

Shader programs run on the GPU and are the core of modern graphics rendering, giving developers per‑pixel coloring capabilities. APIs such as OpenGL, OpenGL ES, DirectX, and the newer Vulkan all rely heavily on shaders.

WebGL brings 3D rendering to the browser, but shaders can also be used for other cool effects. Recently I applied shader techniques to a business page and documented the process.

Large Transparent Background

The original page used a 501 KB transparent PNG as a background, which is hard to compress because of the alpha channel. By splitting the PNG into two non‑transparent JPEGs—one storing the RGB channels and the other storing the alpha channel in the red channel—we reduced the size to 41.5 KB (about 8 % of the original).

The shader samples the two textures, combines them, and reconstructs the original image.

precision mediump float;
uniform vec2 uResolution;
uniform sampler2D uImage;
void main(){
  vec2 st = gl_FragCoord.xy / uResolution;
  vec4 c2 = texture2D(uImage, vec2(st.x, st.y * 0.5)); // Alpha channel
  vec4 c1 = texture2D(uImage, vec2(st.x, st.y * 0.5 + 0.5)); // RGB channel
  gl_FragColor = vec4(c1.xyz, c2.r > 0.6 ? c2.r : 0.0);
}

Moving Background

The original background consisted of a static red gradient with scattered yellow particles. By generating the particles procedurally with shaders, we avoid loading any image assets and gain smooth performance even with many particles.

We first create a gradient background:

vec3 bgColor(){
  return mix(vec3(0.96,0.02,0.16), vec3(0.96,0.25,0.21), y);
}

Then we generate a random noise function and use it to place particles:

vec2 random2(vec2 st){
  return fract(sin(dot(st, vec2(127.1,311.7))) * 43758.5453123);
}

Particles are drawn as lines using a custom line function that smooths the edges with smoothstep. Multiple lines are combined with a maxList helper to keep the brightest value.

float line(float e, float w, float d, float p){
  float e1 = e - w/2.0;
  float e2 = e + w/2.0;
  return smoothstep(e1 - d/2.0, e1 + d/2.0, p) *
         smoothstep(e2 + d/2.0, e2 - d/2.0, p);
}

To animate the particles we add a time‑dependent offset to the fragment coordinates before sampling the noise.

float inFrag(){
  vec2 st = gl_FragCoord.xy / uResolution;
  st *= 60.0;
  st.y += uTime * 2.0;
  float res = noise2(floor(st), fract(st));
  return smoothstep(0.35, 0.5, res);
}

Hand‑drawn Patterns

Complex window patterns can also be generated with shaders. A basic line function draws straight lines, while rayV, rayH, and box functions create rays and rectangles.

float line(float e, float w, float d, float p){
  float e1 = e - w/2.0;
  float e2 = e + w/2.0;
  return smoothstep(e1 - d/2.0, e1 + d/2.0, p) *
         smoothstep(e2 + d/2.0, e2 - d/2.0, p);
}

float rayV(vec2 ep, float w, float d, float dir, vec2 st){
  float pct = line(ep.x, w, d, st.x);
  if((st.y - ep.y) * dir < 0.0) pct = 0.0;
  return pct;
}

float box(vec2 center, float width, float height, float w, float d, vec2 st){
  float l1 = line(center.x, width + w, d, st.x);
  float l2 = line(center.y, height + w, d, st.y);
  return l1 * l2;
}

By combining several lines, rays, and boxes we recreate the original window pattern without any image assets.

Final Composition

We blend the pattern with a shadow function to give depth, then clip the result with a circular mask that mimics the original rounded window.

float shadow(){
  vec2 st = (gl_FragCoord.xy - center) / uResolution.x * 0.5;
  return smoothstep(0.9, 0.3, st.y + 0.5 * st.x * st.x - 0.1);
}

vec3 veins(){
  return mix(veinsBgColor, veinsFgColor, p) * shadow();
}

vec4 clip(vec3 color){
  float r = uResolution.x * 0.4;
  vec2 dxy = gl_FragCoord.xy - center;
  float dist = sqrt(dxy.x*dxy.x + dxy.y*dxy.y);
  float p = smoothstep(0.95, 0.96, dist/r);
  return vec4(mix(color, borderColor, p), 1.0 - p);
}

The final main function renders the veins, applies the circular mask, and outputs the final color.

void main(){
  vec3 res = veins();
  res = circle(res);
  gl_FragColor = clip(res);
}

Conclusion

These three examples show that thoughtful use of WebGL and GLSL can dramatically reduce image dependencies, eliminate large transparent layers, and enable global or background animations. Because shaders operate per‑pixel, they give developers great flexibility to create lightweight, visually striking effects.

Other small shader tricks used in the original page—such as an animated loading bar and a moving highlight over the text—are omitted for brevity.

Image credit: https://unsplash.com/photos/NFs6dRTBgaM by @Ferdinand Stöhr
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Frontend OptimizationglslWebGLShadergraphics programming
Taobao Frontend Technology
Written by

Taobao Frontend Technology

The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.