Boost page rendering performance using <content-visibility> web component

August 2020, I came across Intersection Observer
web API on a random tweet then checked out the MDN API document, I was so excited and wanting to integrate it to improve our page rendering performance. Luckily, there is a React Hook version of intersection observer already, react-intersection-observer
, so it took no times for us to integrate. Since that time Intersection Observer
is my favourite Web API 😍 whenever I need to toggle/animate/trigger components.
The same month, Google Dev Submit 2020 unveiled CSS content-visibility
and contain-intrinsic-size
properties which supports from Chrome 85. It’s shamed I was buried by developing project features and only came across during Xmas holiday. However, this is like the best Xmas surprise 🎁 for me and it takes my excitement to the next level, just two lines of CSS then I can achieve lazy loading, OMG I freaking love it. You can deep dive content-visibility on Google web.dev, a great article to explain how it works.
But, life is not always easy, content-visibility
is still more like an experimental feature and not supporting the other two major browser Safari and Firefox. 😞

Wait a minute… we have Intersection Observer javascript API and content-visibility
CSS solution, why not combine these so we can provide a cross-browsers solution💡 Meanwhile, implement as a web component is the best choice coz it’s lightweight, high performance (shadow DOM) and great browsers compatibility. I spent 12 hours to digest web component and gave a birth of <content-visibility>
v1 🎉
I chose lit-element
base class to create this web component as it’s lightweight and great browser compatibility, especially their web component GitHub starter template is extremely handy makes the whole experience of creating web component zero-brainer.
Install content-visibility
from NPM and start integrating with any JS frameworks (React, Vue, Preact, Angular, VanillaJS and etc).
npm i content-visibility --save

Alright, let’s see some results I tested on three major browsers, Chrome 87, Safari 14 and Firefox 84 and I used the exact same travel blog template (except I removed iframe
) that is used in web.dev Codepen
Rendering frames, Safari comes with an interesting tool, Rendering Frames Timeline, helps you to measure page rendering performance. I want to start with this result to demonstrate how it reduces unnecessary rendering.



Time measurement, Chrome 87 uses CSS solution which completely handles by browser and you can see Rendering
and Painting
time are reduced around 50%
and overall time reduced 1s
.


Safari 14 fallbacks to use Intersection Observer
API to detect if component appears on the viewport. Layout & Rendering time down from 15s
to 8s
and you can easily see not many rendering chunks happening after applied <content-visibility>


Firefox 84 also fallbacks to use Intersection Observer
API.




You probably wondering how many lines I changed for 👆 PageSpeed results, actually just 4 lines 👇

That’s it! Numbers are better than words to tell the story. I already integrated <content-visibility>
web component with my production web application in Preact
. This is just v1 and sure it can be extended and tweak from feedbacks. Give it a try and welcome to fork the source code and deep dive the implementation. I will find a time to write an article about the implementation but not urgent as logic is simple and straightforward.