CSS contain and content-visibility: Performance and Rendering Control

CSS contain and content-visibility help browsers skip work, isolate parts of the page, and render large interfaces more efficiently. They are especially useful for long documents, feeds, accordions, dashboards, and any page with sections that do not all need to be fully processed at once.

Quick answer: Use contain to isolate an element’s layout, paint, size, or style behavior. Use content-visibility: auto when you want the browser to skip rendering off-screen content until it is needed, while still reserving space for it.

Difficulty: Intermediate

You'll understand this better if you know: basic CSS layout, how the browser renders a page, and how box size and overflow work.

1. What Is CSS contain and content-visibility?

contain is a CSS property that tells the browser an element is mostly independent from the rest of the page. That lets the browser make safer performance optimizations. content-visibility is a newer property that lets the browser skip rendering work for content, especially when it is off-screen.

Think of contain as a way to say, “this box should behave more independently,” and content-visibility as a way to say, “the browser can delay drawing this content until it matters.”

2. Why CSS contain and content-visibility Matter

Modern pages often contain long lists, nested components, comment sections, or complex dashboards. Without containment, a change in one part of the page can force the browser to recalculate more of the layout than necessary.

These properties matter because they can:

They are most useful when a page has many independent sections. They are less useful on small pages or on elements that must interact heavily with surrounding layout.

3. Basic Syntax or Core Idea

Containment basics

The contain property accepts one or more containment keywords. A common starting point is contain: layout paint;.

.card {
  contain: layout paint;
}

This means the element’s layout and paint should be treated as more isolated from the rest of the page.

Visibility-based rendering

The content-visibility property commonly uses auto for browser-managed skipping of off-screen content.

.section {
  content-visibility: auto;
}

With auto, the browser can skip rendering the element when it is not visible in the viewport, then render it when it comes into view.

Reserving space with intrinsic size

When the browser skips rendering an off-screen element, it still needs a reasonable placeholder size. That is why contain-intrinsic-size is often paired with content-visibility.

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

This helps avoid layout jumps by reserving approximate space before the content is rendered.

4. Step-by-Step Examples

Example 1: Isolating a component with contain

Use containment on a card or widget that should not disturb the rest of the page when its internal content changes.

.product-card {
  contain: layout paint;
  border: 1px solid #ccc;
  padding: 1rem;
}

This can help a browser limit repaint and layout impact when the card updates internally.

Example 2: Skipping off-screen article sections

For long articles or documentation pages, content-visibility: auto can delay rendering sections that are below the fold.

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

The browser can skip work for sections outside the viewport and still keep the document height stable.

Example 3: Combining size and layout containment

Sometimes a component’s size should not be influenced by its contents. That is when contain: size or a stronger containment value can be useful.

.preview {
  contain: size layout paint;
  width: 20rem;
}

This is useful when you want a fixed-size preview panel that should not grow or shrink based on its children.

Example 4: Containing a dynamic feed item

In a news feed or comment stream, each item can be treated as its own rendering boundary.

.feed-item {
  contain: content;
  margin: 1rem 0;
  padding: 1rem;
}

contain: content is a convenient shorthand for common layout and paint containment behavior, often used for component-like blocks.

5. Practical Use Cases

These properties are most helpful when the page contains many self-contained blocks and the browser can safely treat them as separate units.

6. Common Mistakes

Mistake 1: Using contain when the element must size itself from children

contain: size tells the browser not to let the contents affect the element’s size. That is useful only when you want a fixed or externally controlled size.

Problem: The container collapses or behaves unexpectedly because its children no longer contribute to its size.

.box {
  contain: size;
  border: 1px solid #999;
}

Fix: Use layout or paint containment only, or give the element an explicit size if size containment is intended.

.box {
  contain: layout paint;
  border: 1px solid #999;
}

The corrected version keeps the component isolated without removing its children from normal sizing rules.

Mistake 2: Using content-visibility without reserving space

When the browser skips off-screen rendering, the page may jump if the element has no intrinsic placeholder size.

Problem: The page can reflow noticeably when the hidden content is finally rendered because no fallback size was provided.

.section {
  content-visibility: auto;
}

Fix: Add contain-intrinsic-size so the browser can reserve space.

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

This works better because the layout has a placeholder height before the content is actually rendered.

Mistake 3: Expecting hidden content to be measurable immediately

Elements skipped by content-visibility: auto are not fully rendered until needed. That means their final rendered state may not be available right away for measurement-based workflows.

Problem: The element may not behave like a fully rendered box until it becomes visible, so measurements taken too early can be misleading.

.panel {
  content-visibility: auto;
  contain-intrinsic-size: 400px;
}

Fix: Avoid depending on off-screen rendered details for layout decisions, and provide intrinsic sizing when you need stable space.

.panel {
  content-visibility: auto;
  contain-intrinsic-size: 400px;
  overflow: hidden;
}

The fixed version keeps the section predictable while still allowing rendering work to be deferred.

7. Best Practices

Practice 1: Apply containment to component boundaries

Containment is most effective when used on reusable UI blocks such as cards, panels, and sections. That gives the browser a clear boundary to optimize around.

.widget {
  contain: layout paint;
}

This is better than applying containment to random inner elements because the optimization boundary matches how the UI is structured.

Practice 2: Pair content-visibility with an estimated intrinsic size

When using content-visibility, always think about the placeholder size the browser should use before rendering.

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

A good estimate reduces layout shift and makes scrolling feel stable.

Practice 3: Test the effect before using it everywhere

Containment is not a universal optimization. If a component depends on overlapping elements, outside shadows, or content-driven size, containment can change behavior in ways that are hard to debug.

.panel {
  contain: paint;
}

Start with a narrow use case, measure the result, and then expand only if the page actually improves.

8. Limitations and Edge Cases

A common “not working” complaint is that a section seems to disappear until scrolling. That is usually expected behavior with content-visibility: auto; the fix is to provide a sensible contain-intrinsic-size and only use the property on content that can be deferred.

9. Practical Mini Project

Here is a small document layout that uses both properties in a realistic way. The page has a long article with repeated sections, and each section is optimized to reduce unnecessary rendering work.

article {
  max-width: 70ch;
  margin: 0 auto;
  padding: 1rem;
}

article section {
  content-visibility: auto;
  contain-intrinsic-size: 500px;
  contain: layout paint;
  padding: 1rem;
  margin-bottom: 1rem;
  border: 1px solid #ddd;
}

This setup lets the browser delay rendering off-screen sections while keeping the article’s scrolling structure stable. It also gives each section a clear containment boundary.

10. Key Points

11. Practice Exercise

Try this exercise to check your understanding of containment and rendering skipping.

Expected output: The browser should reserve space for each section, skip rendering off-screen content until needed, and keep scrolling smoother on a heavy page.

Hint: If the page layout jumps when sections appear, increase the intrinsic size estimate.

article section {
  content-visibility: auto;
  contain-intrinsic-size: 650px;
  contain: layout paint;
}

12. Final Summary

contain and content-visibility are performance-focused CSS tools that help browsers do less work. contain creates boundaries that reduce how much an element can affect the rest of the page, while content-visibility lets the browser defer rendering of content that is not currently visible.

They are most valuable on large, component-based, content-heavy pages. The main thing to remember is that these properties are not just about speed; they also change how layout, sizing, and rendering behave. Use them carefully, test them on real content, and pair content-visibility: auto with contain-intrinsic-size whenever you want stable scrolling.

If you want to go further, the next step is to learn more about browser rendering, layout containment, and how overflow, size, and stacking contexts interact with optimized components.