content-visibility and contain-intrinsic-size: Rendering Only What Is Near the Screen
A long article, a documentation page or an infinite feed can contain hundreds of sections, and the browser lays out and paints all of them on load even though only the first screenful is visible. That work delays the first render and makes every later style change more expensive, because layout must be recomputed across the whole document. content-visibility: auto tells the browser it may skip rendering a section's contents until the section nears the viewport. contain-intrinsic-size gives skipped sections a placeholder size so the page does not collapse or jump. This page explains how the two work together, where the savings come from, and the side effects to handle. It belongs to Intrinsic Sizing Techniques in the Mastering Container Queries & Responsive Layouts guide.
Why skipping rendering is safe with containment
Browsers cannot normally skip laying out off-screen content, because that content might affect what is on screen: its size pushes later content down, its floats wrap earlier text, its styles could change anything. content-visibility: auto makes skipping safe by applying containment: layout, style and paint containment always, and size containment while the content is skipped. Containment promises the browser that the element's contents cannot affect anything outside it, so the browser can leave them unrendered without risk of getting the rest of the page wrong.
Size containment is the part that needs help. A size-contained element is laid out as if it had no contents — zero height for a block. Without a placeholder, every skipped section would collapse, the page would be far shorter than it really is, and the scrollbar would grow and jump as sections rendered one by one during scrolling. contain-intrinsic-size supplies the size to use in place of the contents.
The complete implementation
The article below applies content-visibility: auto to each top-level section and reserves an estimated height with the auto keyword, so sections that have been rendered once remember their real size.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>content-visibility for long pages</title>
<style>
body { font: 17px/1.65 Georgia, serif; margin: 0 auto; max-width: 65ch; padding: 1.5rem; }
/* Every section except the first: the first is on screen at load, so
skipping it would only add work. */
.chapter + .chapter {
content-visibility: auto;
/* Placeholder until first render, then the remembered real size.
'auto' is what keeps the scrollbar from jumping on the way back up.
Only the block size matters for a vertical article; the width comes
from normal layout. */
contain-intrinsic-size: auto 900px;
}
/* Anchor targets inside skipped sections still work: navigating to one
renders its section first. scroll-margin keeps it clear of a header. */
.chapter h2 { scroll-margin-top: 4rem; }
</style>
</head>
<body>
<nav aria-label="Chapters">
<a href="#c1">Chapter 1</a> · <a href="#c2">Chapter 2</a> · <a href="#c3">Chapter 3</a>
</nav>
<section class="chapter" id="c1"><h2>Chapter 1</h2><p>Long content…</p></section>
<section class="chapter" id="c2"><h2>Chapter 2</h2><p>Long content…</p></section>
<section class="chapter" id="c3"><h2>Chapter 3</h2><p>Long content…</p></section>
</body>
</html>
The adjacent-sibling selector .chapter + .chapter leaves the first chapter alone. Applying content-visibility: auto to content that is visible on load gains nothing and costs containment bookkeeping; it pays off only for content that starts off screen. The 900-pixel estimate should be close to a typical section's rendered height — the closer it is, the less the scrollbar moves as sections render for the first time.
The key technique: the auto keyword remembers real sizes
The subtle failure without auto shows up when scrolling back. A section scrolls into view, renders at its real 1,400 pixels, scrolls out of view, becomes skipped again — and, without auto, reverts to the 900-pixel placeholder. The page shrinks by 500 pixels above the viewport and everything jumps. With contain-intrinsic-size: auto 900px, the browser records the last rendered size and uses it whenever the section is skipped again.
The syntax takes one or two values per axis: contain-intrinsic-size: auto 900px applies to both axes with the auto behaviour, and the longhands contain-intrinsic-block-size and contain-intrinsic-inline-size let you set only the axis that matters. For vertical documents, the block size is what counts; the inline size is determined by normal layout because the section spans its container.
Side effects to know about
Find in page and anchors. Skipped content remains searchable. Find-in-page matches text in skipped sections and renders them as it scrolls to the match. Fragment links to IDs inside skipped sections work the same way, which is why the example keeps scroll-margin-top on headings; see scroll-margin and scroll-padding for Sticky Headers.
Accessibility. With auto, skipped content stays in the accessibility tree, so screen readers can navigate headings and landmarks throughout the page. Some older implementations exposed skipped content inconsistently; test heading navigation in the screen readers you support.
Layout-dependent script. Code that measures elements with getBoundingClientRect() in skipped sections gets placeholder sizes, and code that expects off-screen images or components to have rendered may find they have not. Intersection-observer-based lazy loading works normally.
Animations and transitions. Animations inside skipped content do not run while it is skipped, which is a benefit for off-screen loops. Scroll-driven animations attached to elements in skipped sections resume when the sections render; see Scroll-Triggered Reveal Animations for reveal effects that coexist with deferred rendering.
Where the savings come from
Rendering a page runs a pipeline for every element: style (computing each property), layout (sizes and positions), paint (drawing into layers) and composite (assembling layers into the frame). For a skipped section, the browser still computes enough style to know the section's own box, but it skips the contents entirely at the layout and paint stages.
That is why the gain depends so strongly on content. A section of plain paragraphs has cheap layout, so skipping it saves little per section, though hundreds of sections add up. A section full of grids, tables, icons and nested components has expensive layout and paint, and skipping it saves a great deal. The same logic explains why content-visibility helps later interactions too: when a style change forces a relayout, skipped sections are excluded from the work, so the page responds faster to state changes long after load.
Measuring the benefit
The gain depends on how much off-screen content there is and how expensive it is. Record a Performance profile of the page load with and without content-visibility, and compare the time spent in Layout and Paint before first contentful paint. Long pages of text often show modest savings; pages with many complex components — tables, charts, deeply nested cards — show large ones. If the numbers do not move, remove it: containment has a small cost, and there is no reason to pay it without a benefit.
Also measure interaction, not only load. Open the page, scroll to the middle, and record a profile while toggling something that forces layout — expanding a disclosure or switching the theme. The Layout event's affected-node count should be far lower with content-visibility than without, because skipped sections above and below are excluded. That improvement is often more noticeable to users than the load-time saving.
Browser support
content-visibility is supported in Chrome and Edge 85+, Firefox 125+ and Safari 18+. contain-intrinsic-size, including the auto keyword, is supported in Chrome and Edge 83+, Firefox 107+ and Safari 17+. In engines without content-visibility, the declarations are ignored and every section renders normally, so the property is safe to ship as a progressive enhancement.
FAQ
What does content-visibility: auto do?
It lets the browser skip layout and paint for an element's contents while the element is far from the viewport. The element still exists in the DOM and accessibility tree; its rendering work is simply deferred until it approaches the screen.
Why do I need contain-intrinsic-size with content-visibility?
A skipped element's contents are not laid out, so the element would have zero height, making the page shorter and the scrollbar jump as sections render. contain-intrinsic-size gives the skipped element a placeholder size so the page height stays close to its real value.
What does the auto keyword in contain-intrinsic-size do?contain-intrinsic-size: auto 500px uses 500px until the element has been rendered once, then remembers its last real size and uses that while it is skipped again. This keeps the scrollbar stable after the user has scrolled past a section.
Does content-visibility hide content from screen readers or search?
No for auto: skipped content remains in the accessibility tree and is searchable with find-in-page, which brings it into view. content-visibility: hidden is different; it behaves like display: none for rendering but preserves the element's rendering state for fast re-showing.
Related
- Intrinsic Sizing Techniques — the parent guide.
- container-type: size vs inline-size — the same size-containment trade-off in container queries.
- Profiling Animations in DevTools — the Performance panel used to measure savings.
- Preventing Flex and Grid Overflow — another intrinsic-size behaviour worth understanding.
Related articles
More pages in the same section.