How to Use content-visibility: auto on Long Pages

This guide is part of CSS Containment & content-visibility, within Rendering & CSS Performance. Long pages — articles with many sections, documentation, product listings with hundreds of items, comment threads, social feeds — make the browser lay out and paint everything on load, even though users see only the first screen or two. On mid-range phones, that initial rendering can take hundreds of milliseconds, delaying LCP and blocking early interactions.

content-visibility: auto lets the browser skip rendering for sections that are offscreen. Applied to the right elements with sensible placeholder sizes, it is one of the highest-return CSS changes available: often a single rule that cuts initial rendering time by more than half. Applied carelessly, it causes scrollbar jumps, anchor links landing in the wrong place, and no gain at all for content near the fold.

Initial rendering time on a 300-item product listing Bar chart comparing style, layout and paint time on load for a long listing page with and without content-visibility auto. Initial rendering time on a 300-item product listing Without content-visibility 540ms auto on every card 210ms auto on groups of 12 cards 120ms Grouping reduces per-element bookkeeping while still skipping offscreen work.

Rapid Diagnosis

  • Profile load with 4x CPU throttling; note the Layout and Recalculate Style durations and node counts.
  • Measure page length in viewport heights; pages over 5–10 screens are good candidates.
  • Identify natural section boundaries: article sections, list groups, cards, comment threads.
  • Check for scripts measuring offscreen content, which would force rendering.

Root Cause Analysis

1. Rendering scales with content, not with what is visible. The browser lays out the whole document.

2. Long pages on slow CPUs. Phones spend several times longer than laptops on the same layout.

3. No natural skip mechanism. Without containment, browsers must render everything to know positions and sizes.

4. Overly fine granularity. Applying content-visibility to thousands of tiny elements adds bookkeeping overhead.

Step-by-Step Resolution

1. Choose the boundary elements

Pick elements that are large enough to matter (several hundred pixels tall) and numerous: article sections, groups of cards, comment threads. For lists, group items into chunks (for example 10–20 cards per group) rather than applying the property to each card.

2. Apply the property below the fold only

css
/* Skip rendering for sections after the first two. */
.article > section:nth-of-type(n + 3),
.product-grid > .group:nth-of-type(n + 2) {
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}
/* trade-off: :nth-of-type thresholds are approximate; on very tall screens the
   third section may already be visible, which costs a little extra work only. */

3. Provide realistic intrinsic sizes

Estimate typical section height per template. With auto, the browser uses the estimate until the section has rendered once, then remembers its real size.

4. Remove scripts that measure skipped content

Replace scroll-position calculations that read every section's geometry with IntersectionObserver, which works with skipped content without forcing it to render.

Load rendering on a long article (mid-range phone) Timeline comparing layout work on load for a long article with and without content-visibility auto. Load rendering on a long article (mid-range phone) Without style layout of all sections paint With auto style layout paint 0ms 200ms 400ms 600ms 800ms 1000ms 1200ms first paint

Verification

Re-profile load and compare Layout and Recalculate Style times. Scroll slowly and quickly through the page and check that content appears without blank flashes and the scrollbar does not jump noticeably. Use find-in-page for text deep in the page and follow anchor links to late sections. Confirm CLS did not increase in the lab and the field.

Worked Example: A Long-Form Publisher

A long-form publisher's feature articles averaged 9,000 words with embedded images and pull quotes, rendering about 6,500 elements. On a mid-range Android device, initial layout took 480ms and LCP p75 was 2.9s. The team wrapped each H2 section in a section element and applied content-visibility: auto; contain-intrinsic-size: auto 1400px from the third section onwards. Initial layout dropped to 110ms, LCP p75 to 2.4s, and TBT by 300ms. Anchor links from the table of contents initially landed a few hundred pixels off; adding scroll-margin-top and generating intrinsic size estimates from word count per section in the build fixed them.

Should this element get content-visibility auto? Decision sequence for whether to apply content-visibility auto to a given element. Should this element get content-visibility auto? Is it visible in the first one or two screens? No — leave it rendered yes no Is it small (under ~200px) and numerous? Group several into one wrapper first yes no Do scripts measure it on load? Replace with IntersectionObserver first yes no Apply content-visibility auto with an auto intrinsic size

Grouping Items in Long Lists

For lists of many small items (cards, rows, comments), applying content-visibility to every item works but creates per-item overhead, and each item's placeholder size must be accurate. Grouping items into chunks gives most of the benefit with fewer, larger boundaries. A server-rendered grid can emit groups of 12 or 24 items in wrapper elements; a client-rendered list can group items in the component. Groups also suit infinite scroll well: each appended page of results becomes a group that the browser can skip once it scrolls out of view.

html
<div class="product-grid">
  <div class="group"><!-- cards 1-12 --></div>
  <div class="group"><!-- cards 13-24 --></div>
</div>
<!-- trade-off: wrapper elements change grid structure; use display: contents
     only if you accept that it disables the group's own box (and containment). -->

Combining with Server Rendering

Server-rendered long pages benefit most, because the full HTML arrives at once and would otherwise all be laid out on load. Emit section wrappers in the server template, so no client-side work is needed to apply the property.

Common Mistakes

  • Applying it to the first screen. Adds work at the moment that matters most.
  • Forgetting contain-intrinsic-size. Skipped sections collapse, the page becomes short, and the scrollbar jumps.
  • Using it on tiny elements. Bookkeeping overhead outweighs the savings.
  • Measuring skipped content in JavaScript. Forces rendering of everything you meant to skip.

Edge Cases

Anchor navigation. Browsers render the target section, but intrinsic size estimates for sections above it can shift the final position; auto sizes and realistic estimates minimise this.

Printing. Skipped content is rendered for printing; no special handling needed.

Images in skipped sections. Images in skipped content are not loaded until the section renders, which acts as lazy loading; keep loading="lazy" anyway for older browsers.

Hash-change navigation in SPAs. Scroll restoration may land slightly off on first visit before real sizes are remembered.

FAQ

How much faster will my page be?

It depends on how much content is offscreen. Long pages often see 50–80% reductions in initial rendering time; short pages see little or none.

Does content-visibility affect SEO?

No. The content stays in the DOM and is accessible to crawlers.

Should I use content-visibility on every list item?

Usually better to group items. Per-item use works but has more overhead and needs accurate sizes for each item.

Does it work with infinite scroll?

Yes. Apply it to each appended page or group, so groups scrolled past are skipped. For very long sessions, combine with virtualization to cap DOM size.

What happens when the user scrolls quickly?

The browser renders sections as they approach the viewport. On very fast scrolls on slow devices, a brief blank area may appear; a reasonable intrinsic size keeps the layout stable while it renders.

Does content-visibility reduce memory use?

Slightly, for rendering data structures, but the DOM is unchanged. Use virtualization if memory is the concern.

Can I use content-visibility on table rows?

Table layout depends on all rows, which limits the benefit; support for containment on table parts is also restricted. Group rows in separate tables or use a grid layout for very long tabular data.

Does content-visibility work in all browsers?

Current versions of Chromium-based browsers, Firefox and Safari support it. Older browsers ignore the property and render everything, which is the same as not using it, so it is safe as a progressive enhancement.

Should I combine it with lazy-loading images?

Yes. Keep loading="lazy" on images in skipped sections; it covers browsers without content-visibility support and makes the intent explicit.

Does it change how the page prints?

No. Browsers render skipped content when printing, so printed output includes every section.