Earlier this year, Chromium 85 was released which low-key contained a new CSS property that completely flew by me at the time. The
content-visibility property allows you to instruct the user-agent to skip all rendering work, including layout and painting until it is needed.
When Is This Useful?
If you have content that is initially hidden or off-screen then those sections, containing text or even multimedia, do not have to be rendered yet. This can dramatically improve page rendering performance since nothing is loaded, even the images or iFrames contained in the sections.
Right off the bat, I can think of several applications for this:
- Everything below the fold on long pages
- Dropdown menus
- Side panels
How To Use It
content-visibility property is basically a shorthand for CSS Containment Spec. The property has three unique values:
visible: this is the default value and yields no effect. The element’s contents are laid out and rendered as normal.
hidden: the element completely skips its contents. The content will not be accessible to user-agent features, such as find-in-page, tab-order navigation, nor will it be selectable or focusable. This is similar in effect to give the element’s contents
auto: the element receives layout, style, and paint containment. If the element is not relevant to the user it also skips its contents. Unlike the
hiddenvalue the skipped contents will remain accessible to user-agent features such as find-in-page, tab-order navigation and must be focusable and selectable.
That means that we can use the following CSS to achieve the effect that a certain element won’t have its content rendered, painted, styled, or any of its media assets loaded until it is needed on-screen.
There is a small catch though. The height of the element will currently be 0 just like when you use
display: none; on the element. This isn’t ideal since you can see the scrollbar shift as elements become visible, which is terrible UI.
To solve this, we can use the
contain-intrinsic-size property to set a placeholder width and height for the element until the actual content is needed and rendered.
Hiding Content With Content-Visibility: Hidden
content-visibility: hidden; hides the content from the user’s view, removes it from user-agent features, and makes the content unselectable and unfocusable just like
display: none; does. The difference lies in the cached rendering state.
display: none;it completely destroys the rendering state. This means that there is effectively no difference between removing
display: none; from an element and rendering a completely new element with the same content.
content-visibility: hidden; however, the cached rendering state is maintained. This means that content can be rendered on the screen much more efficiently. This is great for blocks of content that can be shown/hidden repeatedly like with views in Single Page Applications.
content-visibility was added in Chromium 85 and currently works on recent versions of Chrome, Edge, and Opera. Firefox has deemed it worth prototyping and Safari hasn’t said anything about this feature as of now.
This means that using
content-visibility: hidden; on production sites comes with something to keep in mind. You can’t use
content-visibility: hidden; safely as the only way to hide content. Either use some form of feature detection or combine it with
This simple CSS property can bring exciting performance optimizations to your toolkit. For more information on resources
content-visibility and the CSS Containment Spec check out the following resources:
- content-visibility: the new CSS property that boosts your rendering performance [web.dev]
- content-visibility docs [MDN Web docs]
- MDN Docs on CSS Containment
Thank you for reading. If you have any thoughts on this, let me know in the comments below.
And you can follow me on Twitter here.