Improve pagespeed with content-visibility CSS, is it for you?

Improve pagespeed with content-visibility CSS, is it for you?

Content-visibility is a new CSS property that boosts your rendering performance, according to Google. But is that really so and are there any caveats, or in other words, should you start using it already?

Different tasks are executed on the browser's main thread, preventing it from doing any other work at the same time, such as:

  • Responding to user input;
  • Executing another script.

But if you think that JavaScript alone can be a culprit, think again. The amount of CSS and HTML will impact performance as well. Or to be more precise, the amount of Rendering and Style & Layout work.

What content-visibility does

Web.dev is describing content-visibility as following:

content-visibility enables the user agent to skip an element's rendering work, including layout and painting, until it is needed

By not doing any rendering work on specific elements, you are basically freeing up the main thread, maybe even prioritizing other tasks, such as executing your Javascript slider so that users can already interact with your product image gallery.

This could be ideal to, for example, skip rendering of below-the-fold elements as those won't be visible during initial pageload anyway. By using content-visibility: auto, the browser knows when to start rendering an element. That is: when the element would enter the viewport.

section + section {
content-visibility: auto;
}

With this code, any section after the first section won't be rendered when it isn't in the viewport yet. You could also apply this to every section, but what's the point when you as a developer already know that the first section is above the fold and thus within the initial viewporty anyway!

Rendering performance boost with content-visibility

There definitely is a performance boost using content-visibility:

  • Based on the demo of web.dev, it could lead to a 7x rendering performance boost (in their case equal to 87.1% rendering performance boost);
  • And in the latest Chrome Dev Summit on Youtube, Jake Archibald described how applying content-visibility took the layout time down from 50 seconds to 400 milliseconds. That equals a 99.2% rendering performance win.

Do note that the demo-page that Jake used is 11.8MB and contains 270,438 DOM nodes according to Lighthouse. Lighthouse or PageSpeed Insights would like to see less then 1,500 DOM nodes. So, we could expect such outcome when a browser gets to skip rendering layout-work for so many DOM nodes.

A performance boost with a single line of CSS. Optimizing was never this easy. Obviously, I had to try content-visibility myself. In my case on the homepage of an average website. The performance gains were as following:

  • 19.2% on a Motorola Moto G 2nd Gen;
  • 38.8% rendering improvement on a Samsung Galaxy S20;
  • 41.2% on a Toshiba laptop with Windows 10 and multiple tabs opened in the browser. Obviously, this could skew the results. However, it is likely that users have multiple tabs opened in real life situations as well.

These are the average performance boosts of 4 runs for each setup, using an up-to-date Google Chrome browser. The tested webpage was a large homepage of a Dutch mortgage website, containing 1,172 DOM nodes. This is a screenshot of the test-runs.

Lighthouse and PageSpeed Insights score

Implementing content-visibility might even impact your Lighthouse or PageSpeed Insights score, as less work is done on the main thread. Less blocking time could positively impact the Total Blocking Time metric, which has a weight of 25% towards the overall pagespeed score.

Even for some basic sites, the Total Blocking Time dropped as following:

  • 300 to 140ms for a tiny homepage of a SaaS;
  • 260 to 70ms for an average sized homepage of my web agency;
  • 340ms to 40ms for a larger homepage of a medical center.

These are outcomes of a mobile test using PageSpeed Insights. In some cases, we gained 9 percentage points for the mobile score. Obviously, changes in other metrics such as Largest Contentful Paint also impacted the score, so don't expect the same outcomes when running tests yourself.

Downsides of content-visibility

A must have or rather must implement then, right? It basically equals lazyloading whole HTML portions, as browsers also won't render any child elements of an element that was given content-visibility: auto. Just mark all your below-the-fold elements using a class-name, and attach the content-visibility property to this class.

However, being a new property introduced in Chroem 85 / August 2020, there are still some serious downsides to using content-visibility you should be aware of.

Browser support of content-visibility

Not all browsers already support content-visibility. At time of writing, only Chromium (meaning, Google Chrome and Microsoft Edge) and Opera. This could change though, check content-visibility on caniuse for current browser support.

Lack of browser support isn't really an issue though. This basically is a good example of progressive enhancement.

Dancing scrollbars

Not literally, but as a user keeps scrolling and content is intersecting the viewport, it is being rendered on-the-fly. As it wasn't rendered before, the browser did not give it any dimensions. The contents basically weren't there yet. This equals new contents being inserted, enforcing the scrollbar to adapt to the new height of the page, every time new contents are rendered.

If the user is already confused about how things on the screen work, it’s one less familiar thing for them to cling to as stable and reliable

Eric Bailey on (colouring) scrollbars

This behaviour can be seen in this scrollbar demo. On desktop + Chrome/Edge or Opera, try to scroll by grabbing the scrollbar without getting frustrated.

Placeholder-like solution

There is an additional property you could use to solve this, called contain-intrinsic-size. You could use it as following, next to your content-visibility property.

section + section {
content-visibility: auto;
contain-intrinsic-size: 1px 1000px; /* 1px width, 1000px height */
}

This acts as a placeholder for the soon-to-be-rendered contents. However, you can't know the presumable height of not yet rendered elements. Especially hard to tellas we are in a responsive webdesign era where there are a varies screen-ratios amongst your visitors.

Values which aren't closing to the eventual height of the rendered elements will also lead to dancing scrollbars.

Meet layout-shifts

A scrollbar changing in height often is a sign of layout shifts. Unfortunately, implementing content-visibility also resulted in layout shifts. Important to know is that layout shifts is part of Core Web Vitals and thus future Google ranking.

Luckily, this was already spotted by the Chromium team and a fix was merged into Chrome 88 with release date January 19th, 2021. For up-to-date bèta and release dates, see the chromestatus.com schedule.

Breaking accessibility

Unfortunately, this weren't all caveats yet. Any elements with content-visibility property behaves the same as display: none, when it comes to preserved height (being none) as well as accessibility. Contents aren't announced in some screenreaders such as NVDA, for example when a screenreader user would request a list of headings, but those headings weren't shown yet.

this feature suppresses HTML semantics in assistive tech in favor of faster rendering performance. So use it wisely!

As contents aren't visible for sighted users either until contents are scrolled into the viewport, this isn't a Web Content Accessibility Guidelines failure. Nevertheless, the Chromium team is taking feedback seriously and is already looking into it.

No more smooth scrolling on in-page navigation

On top of that, it could also break in-page navigation when using smooth scrolling via CSS.

Contents not appearing anymore

This is the worst bug-report ever which would annoy any developer. When implementing the content-visibility property, I run into dropdowns not showing anymore. I think this had to do with the element or its parent being toggled from display: none to display: block, or maybe visibility: hidden to visibility: visible.

I couldn't reproduce it anymore this quickly, but also don't really bother anymore either as I got it fixed for my use-case. Be aware though that this could happen.

Conclusion

The new content-visibility property is an easy to implement performance boost. But it does come with some issues. Moreover, I ain't sure where content-visibility might go. Maybe browser vendors choose to improve its behaviour natively, or an "Intent to Remove" might be next instead, as there are quite some caveats and UX issues to fix.

If there are any disadvantages that goes against your type of audience or when you only have small webpages, this property might not yield what you hoped for. On the other hand, if your webpages are for example quite heavy in JavaScript, chances are most performance gains can be found in those area's instead.

Further reading and watching

In all cases and for the time being: despite only being one CSS property, use it wisely!