CSS Performance and Optimization
Reduce layout thrashing, compositing costs, and selector overhead using will-change, content-visibility, contain, and efficient animation techniques.
Overview
Key Points
- •Only transform and opacity can be animated on the GPU without triggering layout or paint
- •will-change: transform promotes an element to its own compositor layer before animation starts
- •Overusing will-change wastes GPU memory; apply it only to actively animating elements
- •content-visibility: auto skips rendering for off-screen elements, dramatically reducing initial paint time
- •contain: layout prevents changes inside the element from triggering layout in the rest of the page
- •contain: paint clips children to the element border, enabling separate paint records
- •contain: strict is shorthand for layout + paint + size
- •Selector performance: avoid deep descendant selectors; CSS reads selectors right-to-left
Examples
Efficient animations with compositor-only properties
/* Good: transform and opacity only touch the compositor layer */
.card-hover {
transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
}
.card-hover:hover {
transform: translateY(-4px) scale(1.02);
box-shadow: 0 12px 32px rgba(0,0,0,0.15);
/* box-shadow triggers paint but not layout, acceptable */
}
/* Avoid animating layout-triggering properties */
/* Bad: */
.bad-hover:hover {
margin-top: -4px; /* triggers layout recalc for all siblings */
width: 102%; /* triggers layout */
}will-change for pre-promoted layers
/* Apply will-change before animation, remove after */
.menu-panel {
will-change: transform; /* promoted before transition triggers */
transition: transform 0.3s ease;
}
.menu-panel.open {
transform: translateX(0);
}
.menu-panel.closed {
transform: translateX(-100%);
}
/* For elements that animate constantly */
.spinning-loader {
will-change: transform;
animation: spin 1s linear infinite;
}
/* Remove will-change if animation is conditional */
.card:not(:hover) {
will-change: auto; /* free GPU memory when not animating */
}will-change is a hint to the browser to promote the element to its own layer ahead of time, reducing the first-frame cost of an animation.
content-visibility: auto for long pages
/* Great for pages with many sections */
.page-section {
content-visibility: auto;
/* Provide an estimated height so the scrollbar is accurate */
contain-intrinsic-size: 0 600px;
}
/* The browser skips rendering off-screen sections entirely */
/* Rendering happens lazily as sections scroll into view */
/* For individual list items in a very long list */
.feed-item {
content-visibility: auto;
contain-intrinsic-size: 0 80px; /* approximate item height */
}content-visibility: auto can reduce initial page render time by 40-80% on long pages.
CSS containment for layout isolation
/* Contain layout side effects of a widget */
.ad-widget {
contain: layout paint; /* changes here do not trigger outer layout */
overflow: hidden; /* paint containment requires this or clip-path */
}
/* Strict containment for independent components */
.data-grid {
contain: strict; /* = layout + paint + size */
width: 100%;
height: 400px;
overflow: auto;
}
/* Style containment prevents custom counters escaping */
.article {
contain: style;
counter-reset: section;
}
.article h2::before {
counter-increment: section;
content: counter(section) ". ";
}Common Mistakes
- Applying will-change to every element as a blanket optimization (it wastes GPU memory)
- Animating width, height, top, or left, which trigger full layout recalculation every frame
- Forgetting contain-intrinsic-size with content-visibility: auto causing layout instability
- Removing will-change immediately on animation start instead of before it
Note
Before optimizing, measure. Use Chrome DevTools Performance tab to record a frame and check for long paint or layout tasks. Only apply will-change and contain to elements where profiling shows actual bottlenecks.
Exercises
Write CSS to style the HTML scaffold. The preview updates live — when it looks right, mark as done.
Completed: 0 / 2 exercises
Knowledge Check
Question 1 of 3