SiteTidy
HomeGuidesCSS content-visibility: Skip Rendering Work Without Making the Page Jump
Performance

CSS content-visibility: Skip Rendering Work Without Making the Page Jump

A practical guide to content-visibility and contain-intrinsic-size: where they save rendering work, how bad size estimates cause scroll jumps, and when not to use them.

Published on September 5, 2026

Long pages have a slightly absurd performance problem: the browser can spend real time laying out and painting content the user cannot see yet.

For some pages that work is unavoidable. For others, CSS can tell the browser that whole sections below the fold are safe to postpone.

The property is content-visibility.

The attractive demo is usually one line:

section {
  content-visibility: auto;
}

That is enough to make a synthetic rendering benchmark look better. It is not enough for a production rollout.

The awkward part is geometry. If the browser skips a section’s contents, it still needs to know roughly how much space that section occupies. Get that wrong and the scrollbar changes length, content shifts as sections are revealed, or deep links land somewhere unexpected.

That is why I would treat content-visibility and contain-intrinsic-size as a pair rather than as two unrelated CSS features.

What content-visibility: auto is actually buying you

A browser normally has to do more than download HTML before pixels appear. It builds style information, calculates layout, paints content and composites the result.

On a long document, a lot of that work may belong to sections several screens below the current viewport.

content-visibility: auto allows the browser to skip rendering work for an element when that content is not relevant to the user. As the element approaches the viewport, the browser renders it normally.

A useful first pass looks like this:

.article-section {
  content-visibility: auto;
  contain-intrinsic-size: auto 800px;
}

MDN’s current example uses the same pattern: content-visibility: auto to skip off-screen rendering and contain-intrinsic-size: auto <length> to provide a placeholder size until the real size is known.

The performance win is therefore not “CSS makes the section load later”. Network loading and rendering are different things. Images, stylesheets or scripts can still be requested according to their normal loading rules.

What you are deferring is work the rendering engine would otherwise perform for content that is not currently useful on screen.

Start with large, independent chunks

I would not sprinkle content-visibility: auto onto every div on a page.

Use it where the browser can skip a meaningful amount of work at once:

<main>
  <section class="article-section">...</section>
  <section class="article-section">...</section>
  <section class="article-section">...</section>
  <section class="article-section">...</section>
</main>

Good candidates tend to be substantial, vertically stacked sections such as:

  • long documentation chapters;
  • product-result groups;
  • large comment threads;
  • feed sections;
  • complex dashboard panels that sit far below the fold;
  • article sections containing diagrams, tables or sizeable DOM subtrees.

A tiny card with six DOM nodes is usually not worth turning into its own rendering island. There is overhead and complexity in any optimisation. The unit of containment should be big enough that skipping it can plausibly matter.

The tempting approach is to optimise by selector count: “we applied this to 400 cards” sounds impressive. I would optimise by avoided work instead.

Why contain-intrinsic-size matters

Suppose a below-the-fold section is actually 1,200 pixels tall.

If the browser skips its contents and has no useful stand-in size, the page cannot reserve that 1,200-pixel space accurately. When the section eventually renders, the document geometry can change.

That is where contain-intrinsic-size helps:

.article-section {
  content-visibility: auto;
  contain-intrinsic-size: auto 900px;
}

The 900px is an initial fallback estimate.

The auto part is more interesting. Current MDN documentation describes auto <length> as allowing the browser to remember the element’s real rendered size after it has been rendered, then reuse that remembered size when the content is skipped again.

That means the estimate matters most before the element has been observed at its real size.

You do not need clairvoyance. You need an estimate that is sane enough to avoid gross geometry changes on first reveal.

A bad estimate can turn a performance win into visible jank

Take a page containing twenty results groups that are normally around 600 to 900 pixels tall.

This is a poor default:

.results-group {
  content-visibility: auto;
  contain-intrinsic-size: auto 50px;
}

The browser initially believes those groups are tiny. As the user scrolls and groups render, their real height replaces that placeholder. The document grows under the user.

The opposite can be just as unpleasant:

.results-group {
  content-visibility: auto;
  contain-intrinsic-size: auto 5000px;
}

Now the initial document is wildly too tall, and it contracts as real content is measured.

MDN’s current contain-intrinsic-size example demonstrates exactly this class of problem: inaccurate intrinsic sizes can make the scrollbar and scroll position jump as elements are rendered and their real dimensions replace the estimate.

I would derive the fallback from real content rather than choose a round number because it looks tidy in CSS.

If your sections cluster around 720 pixels, use something near that. If two kinds of section have very different geometry, give them separate estimates.

.article-section {
  content-visibility: auto;
  contain-intrinsic-size: auto 760px;
}

.related-tools {
  content-visibility: auto;
  contain-intrinsic-size: auto 420px;
}

The estimate does not have to be perfect. It should not be absurd.

Do not confuse this with lazy loading

content-visibility does not replace image lazy loading, route-level code splitting or sensible script loading.

Those techniques attack different costs.

For an image:

<img
  src="/images/diagram.webp"
  alt="Request flow diagram"
  loading="lazy"
  width="1200"
  height="700"
>

loading="lazy" can defer the network request for the image.

content-visibility: auto can allow rendering work for the containing section to be skipped while it is off screen.

You can use both when both costs exist.

I would be suspicious of any performance recommendation that treats one CSS declaration as a replacement for resource prioritisation. A page can avoid painting an off-screen section and still waste megabytes downloading assets the user never reaches.

content-visibility: hidden is a different tool

There are two values people often mentally group together even though their use cases differ:

.panel {
  content-visibility: auto;
}

and:

.panel {
  content-visibility: hidden;
}

auto is the value I would reach for when I want the browser to decide when off-screen content can be skipped.

hidden is explicit. The element’s contents are skipped until you change the property. MDN notes a useful difference from display: none: hidden content can preserve rendering state, which can make showing it again cheaper.

That makes hidden interesting for application UI that is repeatedly shown and concealed.

It does not make it a drop-in semantic replacement for display: none.

If something must be absent from interaction, accessibility or layout for application correctness, choose the mechanism that expresses that requirement directly. Performance should not quietly change the semantics of your UI.

Accessibility is where simplistic advice becomes dangerous

A particularly important detail is that content-visibility: auto is not equivalent to removing content from the accessibility tree.

Current MDN guidance explicitly warns that off-screen content using auto can remain available to features such as find-in-page and accessibility APIs even while rendering work is skipped.

That is usually a feature. A long article should not become invisible to assistive technology merely because its tenth section is below the visual viewport.

It also means this is wrong thinking:

.offscreen-sensitive-content {
  content-visibility: auto; /* not an access-control mechanism */
}

If content should genuinely be hidden from assistive technology, use the appropriate HTML/ARIA semantics for that state. MDN specifically points to aria-hidden="true" when the intention is to remove an element from the accessibility tree.

Do not use rendering containment as privacy, permissions or UI-state logic.

Find-in-page changes how “off-screen” should be understood

One of the better properties of content-visibility: auto is that skipped content can still participate in browser features such as find-in-page.

That matters on documentation sites.

Imagine a 15,000-word troubleshooting guide. Rendering every code block and table immediately may be expensive, but a user pressing Ctrl+F still expects the browser to locate text in section 17.

A home-grown virtualised document can easily break that expectation because the DOM for section 17 may not exist yet.

content-visibility is interesting precisely because the document can remain a real document while the rendering engine avoids some visual work.

I would strongly prefer that over JavaScript virtualisation for long, mostly static reading pages unless profiling proves the CSS approach is insufficient.

Sticky, absolute and cross-section layout deserve testing

Containment works best when the section is genuinely self-contained.

If descendants visually escape the section, participate in unusual positioning relationships or depend heavily on geometry elsewhere in the page, test carefully before applying containment.

The same goes for sticky UI.

A simple article section containing headings, paragraphs, images and code blocks is a much easier candidate than a section whose descendants are designed to overlap neighbouring sections or remain sticky relative to a larger scrolling ancestor.

The point is not that position: sticky automatically makes content-visibility unusable. It is that containment changes what the browser is allowed to reason about independently, so layout with deliberate cross-boundary relationships deserves actual browser testing rather than assumption.

Avoid the hero and other above-the-fold critical content

This should be obvious, but it is easy to over-apply a successful optimisation.

I would not put content-visibility: auto on the main hero, the likely LCP element, primary navigation or a form the user is expected to interact with immediately.

The browser already needs those elements now. Asking it to consider skipping them does not address the real bottleneck.

The sweet spot is content that is expensive enough to matter and sufficiently far away that postponing its rendering is useful.

That is also why this technique tends to become more valuable on genuinely long pages rather than landing pages with four modest sections.

Measure rendering, not just Lighthouse’s final score

A Lighthouse score can tell you that something changed. It cannot tell you whether content-visibility is the reason your application now feels better or whether your size estimates introduced a new scrolling problem.

I would record a representative long page in browser performance tooling and inspect:

  • style and layout time during initial load;
  • paint work before the first interaction;
  • long tasks associated with rendering large below-the-fold subtrees;
  • layout shifts while scrolling through sections for the first time;
  • scrollbar stability;
  • interaction responsiveness while previously skipped content becomes visible.

Test on a slower device as well as a development workstation. Saving 15 ms on a powerful desktop may become a much more meaningful reduction on a mid-range phone.

And scroll the page. A benchmark that stops after initial load can miss the cost you merely moved later.

The correct question is not “did initial rendering get faster?” It is “did we move rendering work to a better time without creating a noticeable bill when the user reaches it?”

A practical rollout

I would start with one of the longest real pages in the application.

Profile it before changing anything. Identify a few large, below-the-fold sections that consume measurable rendering time. Apply content-visibility: auto to those sections, not globally.

Then give each section type a realistic initial intrinsic block size:

.guide-section {
  content-visibility: auto;
  contain-intrinsic-size: auto 700px;
}

If width is already determined by normal block layout, a block-axis estimate is often what you actually care about. The CSS containment family also exposes logical-axis properties such as contain-intrinsic-block-size when you want that intent to be explicit.

For example:

.guide-section {
  content-visibility: auto;
  contain-intrinsic-block-size: auto 700px;
}

Then test:

  1. normal page load;
  2. fast scrolling from top to bottom;
  3. browser find-in-page for text near the bottom;
  4. keyboard navigation;
  5. deep links to headings below the fold;
  6. back/forward navigation and restored scroll positions;
  7. responsive layouts where section height changes substantially.

If the page gets faster but the scrollbar visibly changes length as you scroll, the implementation is not finished.

Use CSS feature detection if the fallback matters

This is a progressive performance enhancement. The page should still work if a browser ignores the declaration.

That gives you a clean fallback story:

@supports (content-visibility: auto) {
  .guide-section {
    content-visibility: auto;
    contain-intrinsic-size: auto 700px;
  }
}

You may not need the @supports block if unsupported properties simply being ignored is sufficient for your stylesheet. I would use it when the related containment declarations or fallback rules are easier to reason about as one feature bundle.

Correctness should never depend on skipped rendering.

This belongs after the obvious performance fixes

If your page ships a 4 MB hero image, blocks rendering on third-party JavaScript and waits 1.5 seconds for HTML, content-visibility is not where I would start.

Fix the large, causal bottlenecks first.

SiteTidy’s 103 Early Hints guide covers one way to use otherwise idle server think time when critical resources are predictable. That is a completely different part of the loading path.

content-visibility becomes compelling when the browser has already received the document and the remaining problem is too much rendering work for content the user has not reached.

That distinction keeps the optimisation honest.

What I would ship

For a long documentation or content-heavy page, I would happily ship content-visibility: auto on substantial below-the-fold sections after profiling confirms that rendering them is expensive.

I would pair it with a realistic auto <length> intrinsic-size fallback, test scrolling and deep linking, and leave above-the-fold content alone.

I would not apply it mechanically to every component in a design system, and I would not use it as a substitute for lazy loading, accessibility state or proper application visibility semantics.

The property is valuable because it lets the browser avoid work it can prove is unnecessary right now. The implementation stays good only when the geometry you give the browser is believable enough that deferring that work remains invisible to the user.

References

Ready to audit your site?

Put this guide into practice immediately using our free tools.

Browse 180+ Free Tools