content-visibility
Lets the browser skip rendering content that isn’t visible, speeding up long pages.
- Initial value
visible- Inherited
- No
- Animatable
- discretely, e.g. with transition-behavior: allow-discrete
- Applies to
- elements for which size containment applies (not plain inline elements or internal table elements)
- JavaScript
element.style.contentVisibility = "auto"
Example
#.comment {
content-visibility: auto;
contain-intrinsic-size: auto 44px;
}<style>
.comment { padding: 10px 12px; border-radius: 12px; background: #18181b; font-size: 14px; }
.comment + .comment { margin-top: 8px; }
.comment strong { display: block; }
.comment p { margin: 0; color: #a1a1aa; }
</style>
<article class="comment"><strong>Ania</strong><p>Grid finally started clicking for me.</p></article>
<article class="comment"><strong>Kuba</strong><p>Grid template areas are the best part of the module.</p></article>
<article class="comment"><strong>Ola</strong><p>Could use more examples with auto-fill.</p></article>
<article class="comment"><strong>Tomek</strong><p>Done, time for the wrap-up exercise.</p></article>In such a short thread you won’t see the effect, since all the comments fit on screen. In a long discussion, the browser only renders the comments near the viewport, and gives the rest 44px of placeholder height until it learns the real one.
Definition and usage
#The content-visibility property decides whether the browser even bothers laying out and painting an element’s contents. The value auto skips work on pieces that are far off-screen, and comes back to them once the user scrolls closer. On long pages with many sections, such as articles, documentation, or comment lists, this can noticeably shorten the first render.
A skipped element doesn’t know its own height, so without a hint it would have zero pixels, and the scrollbar would jump around while scrolling. That’s why auto pairs with contain-intrinsic-size, which supplies a placeholder size. Writing contain-intrinsic-size: auto 500px means: start at 500px, and after the first render, remember the real size. One value applies to both dimensions, two mean width and height.
The value hidden always skips the content, similar to display: none on the children, but leaves the element itself with its border and padding, and the browser can keep the results of earlier renders, so showing it again is faster. It suits cards and panels that get hidden and shown often. Content hidden with hidden isn’t available to screen readers or on-page search, while with auto it stays available.
The value auto always turns on layout, style, and paint containment, just like contain: content. In practice, descendants that stick out past the element get clipped, and the element becomes a containing block for absolutely positioned children.
Syntax
#content-visibility: visible | hidden | auto;
contain-intrinsic-size: none | [ auto? <length> ]{1,2};Values
#- Normal rendering. The badge sticks out past the card’s corner. This is the default value.
- The card is on screen, so it renders normally, but look at the corner: the badge got clipped, because
autoalways turns on paint containment. Off-screen, the browser would skip the whole content. - The content isn’t rendered. Only the card remains, with its padding and border, which has no height without content.
hidden + contain-intrinsic-size
with a placeholder size
The placeholder size holds the empty card’s height, so nothing around it jumps.
Values in practice
#visible
.demo { content-visibility: visible; }auto
auto always turns on paint containment. Off-screen, the browser would skip the whole content..demo { content-visibility: auto; }Browser support
#Newly available · since 2024
Works in the current versions of all major browsers. Older versions may not support it.
- Chrome
- Edge
- Firefox
- Safari
Good practices
#- Use
content-visibility: autoon repeating blocks with substantial content, such as article sections or comments in a long thread, not on single small elements. The gain comes from skipping many blocks at once. - Always add
contain-intrinsic-size: autowith an estimated size, so the scrollbar doesn’t jump around. The wordautoremembers the real size after the first render. - Don’t use
autoon elements that need something to stick out, such as dropdown menus or speech bubbles. Paint containment will clip them.
Related entries
#- containPromises the browser that an element’s interior doesn’t affect the rest of the page, so it can limit layout recalculation and painting.
- displayDetermines how an element behaves in the page layout and how it lays out its children.
- visibilityHides an element but leaves behind the empty space it occupied.
- container-typeTurns an element into a container that @container rules can query for its size. Also covers container-name and the container shorthand.
Spotted a mistake or missing an example? Write to us.