Rendering Performance
Overview
Writing CSS is easy; writing performant CSS is incredibly difficult. The browser's rendering engine operates in a strict pipeline: 1. Layout (calculating box math), 2. Paint (drawing the pixels), 3. Composite (layering everything together via the GPU). Animating 'Layout' properties (like width or margin) is catastrophic because it forces the browser to recalculate the math for the entire webpage 60 times a second (Layout Thrashing). To achieve silky-smooth 60fps animations on cheap mobile phones, you must exclusively animate 'Composite' properties, which bypass the CPU and run entirely on the hardware-accelerated GPU.
Syntax
/* --- TERRIBLE PERFORMANCE (Layout Thrashing) --- */
.bad-button {
width: 100px;
transition: width 0.3s;
}
.bad-button:hover {
width: 150px; /* Forces the entire DOM to recalculate math! */
}
/* --- PERFECT PERFORMANCE (Hardware Accelerated) --- */
.good-button {
transform: scale(1); /* Composite Property! */
transition: transform 0.3s;
}
.good-button:hover {
/* Scales visually, but mathematically the box never changes size,
so the rest of the page layout is unaffected! */
transform: scale(1.5);
}
/* The WILL-CHANGE Optimization */
.heavy-element {
/* Gives the browser a head-start to allocate GPU memory! */
will-change: transform, opacity;
}Common Pitfalls
- The 'will-change' trap. Beginners often apply
will-change: allto the<body>thinking it will magically speed up the site. It actually does the opposite.will-changeforces the browser to reserve heavy GPU RAM. Applying it globally will instantly crash mobile browsers. Only apply it to highly complex elements right before they animate. - Animating
box-shadow. While it seems harmless, painting complex shadows requires massive CPU calculations. Animating a shadow's blur radius will cause heavy lag. The optimized hack is to use a pseudo-element with the shadow pre-rendered, and simply animate itsopacity.
Interview Questions
transform (translating, scaling, rotating) and opacity. Animating anything else (width, top/left, color) forces the browser to hit the CPU.
Real-World Example
The 60fps optimized way to animate a complex Box Shadow on hover.
.card {
position: relative;
}
/* Pre-render the heavy shadow on an invisible ghost element */
.card::after {
content: "";
position: absolute;
inset: 0;
box-shadow: 0 20px 40px rgba(0,0,0,0.5);
opacity: 0; /* Hidden by default */
transition: opacity 0.3s ease; /* GPU Accelerated! */
}
/* Just fade the ghost element in! The GPU handles this effortlessly. */
.card:hover::after {
opacity: 1;
}Check Your Knowledge
Test your understanding of Rendering Performance with these quick questions.