--- title: "Visibility-aware rendering" category: performance status: optional url: https://webspecification.com/spec/performance/visibility-aware-rendering/ updated: "2026-07-06T00:00:00.000Z" sources: - title: "CSS Containment Module Level 2" url: "https://drafts.csswg.org/css-contain-2/" publisher: "W3C CSSWG" - title: "MDN — content-visibility" url: "https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/content-visibility" publisher: "MDN" - title: "Intersection Observer" url: "https://www.w3.org/TR/intersection-observer/" publisher: "W3C" - title: "MDN — Intersection Observer API" url: "https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" publisher: "MDN" source_repo: undefined licence: CC-BY-4.0 --- # Visibility-aware rendering > Use `content-visibility` with `contain-intrinsic-size` to skip layout and paint for off-screen content, and Intersection Observer to drive lazy behaviour, instead of scroll and resize listeners. ## What it is Two platform primitives for "do work only when content is actually visible". **`content-visibility: auto`** is a CSS property from the Containment module. It tells the browser it may skip rendering work — layout, style, paint — for a subtree while that subtree is off-screen. When the element scrolls near the viewport, the browser renders it as normal. **Intersection Observer** is a Web API that fires a callback when an element crosses a configurable threshold relative to the viewport (or another scroll root). It replaces hand-rolled `scroll` and `resize` listeners that ran on every frame. ## Why it matters - **Long pages and card grids get cheaper.** A page with hundreds of sections, product cards, or comments pays the layout and paint cost for all of them on every change. `content-visibility: auto` reduces that to just what is on screen, often a multiple-times reduction in rendering time on initial load and interaction. - **Scroll handlers stop being the bottleneck.** `scroll` listeners fire dozens of times per second on the main thread. Intersection Observer hands the work to the browser's compositor and only wakes your code at the threshold you asked for. - **Built-in primitives beat libraries.** Lazy-init for embeds, "load more" triggers, viewport-driven analytics, and reveal animations all collapse to the same small API. ## How to implement **`content-visibility` on long, repeating sections.** Always pair it with `contain-intrinsic-size` so the browser can reserve layout space for the skipped subtree: ```css .card, article > section { content-visibility: auto; contain-intrinsic-size: auto 600px; } ``` The intrinsic size is a placeholder used until the real content is rendered. Pick a value close to the real rendered size of the block. **Intersection Observer for everything `loading="lazy"` doesn't cover.** Native `loading="lazy"` on `` and `