DEV Community

loading...
Cover image for I made my website 28ms faster with content-visibility

I made my website 28ms faster with content-visibility

Chris Bongers
I write daily web development tips that help you become a more efficient developer. 兩領∴
Originally published at daily-dev-tips.com 2 min read

You might think, what is 28ms? If you are a big advocate of speeding up the web and getting perfect scores on Eleventy's speedlify dashboard, it's a lot!

Not that I was doing bad, as you can see in the screenshot below. I just wanted to get full 100's and get the full potential out of my website.

Speedlify score Daily Dev Tips

Making use of content-visibility

I read about this CSS property a while ago. But never got round to implementing and testing it.
That is until today, so let's see what it actually does.

The content-visibility has three values we can use:

  • visible (no effect, basically how it was before)
  • hidden (a mix between display: none and visibility: hidden, it starts on display hidden, afterwords becomes visibility hidden)
  • auto (This is the one we are looking at. It will only render this element once the browser needs it!)

So how can we add it to elements?

.element {
    content-visibility:auto;
}
Enter fullscreen mode Exit fullscreen mode

I've added this on my homepage to the article-list and footer elements.

Before content-visibility

To give you a better understanding, I did a lighthouse test before these changes.

Before content-visibility

But more important is the actual trace where we can check the total time.

Lighthouse trace

After adding content-visibility

And then, after adding the content-visibility to those two elements, I've rerun the test.

Before content-visibility

And the trace:

Lighthouse trace

That means it was 443ms and is now 415ms, which means + 28ms win!

Conclusion: There is no downside to not adding the auto one. It can only benefit your website, even the small numbers matter.

Making sub-pages faster

I even added my content-visibility on the post pages, where the main content is set to auto.

The following screenshot is a before rendering:

Before content-visibility

And this is the after rendering:

After content-visibility

As you can see, it improved my score overall.
And adding content-visibility made the Time to Interactive 1.1s faster.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Discussion (37)

Collapse
marcellothearcane profile image
marcellothearcane

How do you handle the scrollbar?

Collapse
dailydevtips1 profile image
Chris Bongers Author

Not sure what you mean by that?
On the auto setting it handles the load on scroll for you, or am I misunderstanding your question?

Collapse
marcellothearcane profile image
marcellothearcane

Here's my website with content-visibility on: 5f6c55859d590d0007b1d834--tillys-w...

On the gallery page especially, watch scroll bar as you scroll up and down. It changes size and jumps about which is annoying

Thread Thread
dailydevtips1 profile image
Chris Bongers Author

I see! interesting!

You can add the following property, which should be helping with the scrollbar issue:

contain-intrinsic-size: 250px;

Have a play around with that 250px it's whatever it shows upfront.

More info:
stackoverflow.com/questions/636515...

Another option could be wrapping those multiple divs into 1 big one just for the content-visibility? (Not sure, but thinking out loud)

Thread Thread
marcellothearcane profile image
marcellothearcane • Edited

The problem is each div can have a wildly different height based on content and the browser width (because of responsive image layouts).

I've done it on the divs because a) they are 'slices' from my CMS so it was easy, and b) because if the top of the div is visible on page load, there's no benefit.

I'm messing around with ResizeObserver and can remove the content-visibility once the element is rendered which fixes the issue after the initial scroll-down:

// Vue
mounted () {
  const observer = new ResizeObserver(entries => {
    for (const entry of entries) {
      if (entry.target.getBoundingClientRect().height > 0) {
        observer.unobserve(entry.target)
        entry.target.classList.remove('content-visibility-auto')
      }
    }
  })

  for (const element of document.querySelectorAll('.content-visibility-auto')) {
    observer.observe(element)
  }
}

(yes I'll unobserve everything beforeDestroy, this is just testing )

They aren't massive pages, so removing it isn't a problem after the initial load.

Thread Thread
dailydevtips1 profile image
Chris Bongers Author

Awesome, making use of what we have for now.
Unfortionally it's a not stable function yet. I had this issue where it hides half my divs on my detail pages. :(

Thread Thread
marcellothearcane profile image
marcellothearcane

This version's a bit more stable: 5f6c7268798c4d000721ae4b--tillys-w...

I used the ResizeObserver above to work out an average height value for the contain-intrinsic-size too.

A fun project, thanks for sharing this css trick!

Thread Thread
dailydevtips1 profile image
Chris Bongers Author

That seems really great!
Scrolls nice

Thread Thread
idarek profile image
Dariusz Wickiewicz

What I noticed now, with lazy loading implemented on images the scroll bar also behave like that hence dont think is totally avoidable.

Thread Thread
marcellothearcane profile image
marcellothearcane • Edited

The images are meant to have height attributes, so it knows what size it is before it actually loads it. In theory.

There must be a point when too much JS outweighs the benefits that it is meant to add. Ah well, it's not too bad and it's faster than the old site!

Thread Thread
dailydevtips1 profile image
Chris Bongers Author

Yeah, it's always a mix of using too much JS for "simple" things and having a fast website.
Pretty hard to find a silver lining in there.

Collapse
sandeshsapkota profile image
sandeshsapkota

Hi Chris, I am quite excited with this property and seems yet to be supported by many browsers. but quite confused with your screenshots. content-visibility property skips the rendering, layouting and painting of the elements which have a direct impact on rendering performance which we can see on the rendering on summary tab. in your screenshot it has increased by 1ms from 12ms to 13ms. what is happening ?

Collapse
dailydevtips1 profile image
Chris Bongers Author

Yes, not too sure how that works.
On paper, it should indeed cut down on that, but somehow it cuts down on other parts?

I don't quite know how it counts, but you are right it's very weird it doesn't make that less.

Collapse
sandeshsapkota profile image
sandeshsapkota

Yes. as this blog tells web.dev/content-visibility/ it has major impact on rendering.

Collapse
pk2 profile image
pk2

You measure it wrong. content-visibility will cut rendering time not total and you have different idle time!

Collapse
dailydevtips1 profile image
Chris Bongers Author

Measuring the Total blocking time seems pretty reliable?
That's what it comes down to cutting on.

Collapse
pk2 profile image
pk2

Check this article
web.dev/content-visibility/
Idle can be +- few seconds.

Thread Thread
dailydevtips1 profile image
Chris Bongers Author

Yeah I've seen this one indeed
Still not sure, it will still show as total blocking time done in the test.

Collapse
jfbrennan profile image
Jordan Brennan

Thanks dude! Adding content-vis-auto helper class to M- now...

Collapse
dailydevtips1 profile image
Chris Bongers Author

Your welcome, that's an awesome idea actually!
Heading back to my code-cave

Collapse
tinny77 profile image
tinny77 • Edited

Remember to specify the height of the section you are going to hide with contain-intrinsic-size otherwise you will get jumps and scrollbar stange behaviours while scrolling your page. I needed a while to find out I missed the height property on my last project and that was the cause of the strange behaviour...

Collapse
dailydevtips1 profile image
Chris Bongers Author

Yes indeed check the comment above, marcello had the same issue. Did not see it before but indeed valid point 弘

Collapse
axel186 profile image
Roman Axelrod

Very existed about the feature and waiting to play around with it since August...
It supported only from "Chrome v85".

I still suck with Chrome v84 :(
Maybe because I am using Linux...

Collapse
dailydevtips1 profile image
Chris Bongers Author

Ah that sucks, might be on delay indeed, mac is on 85 already.
But a very exciting feature, hopefully, it will become a mainstream one.

Collapse
axel186 profile image
Roman Axelrod

Anyway, very excited about your results and waiting patiently to the new version ;)
Thank you!

Collapse
madza profile image
Madza • Edited

Lighthouse looks so good on the dark theme
And agree on 28ms, its all the small things that count the most

Collapse
dailydevtips1 profile image
Chris Bongers Author

100% I was reading this article that for every MS your slower you lose 7% of the people.

Collapse
aspiiire profile image
Aspiiire

What about old browsers support? :(

Collapse
dailydevtips1 profile image
Chris Bongers Author

What about it? haha
They don't contribute to your page speed scores, and they are not negatively affected by having this.

It will just be the same as not having it, but the point of having it is to speed up in modern browsers.

Old browsers are not fast by definition.

Collapse
mitchobrian profile image
Michael Palmer

What about add this to html,body in main css?!

Collapse
dailydevtips1 profile image
Chris Bongers Author

I don't think that will work, you'll end up with a flickering website and no profit since it will immediately fire is my assumption.

Collapse
winston0410 profile image
John Winston

Should we then just use content-visibility: auto for all elements, if it has no performance downside but benefits?

Collapse
dailydevtips1 profile image
Chris Bongers Author

Good question John,
It a thin line, so doing it will have no performance downside, but you might get issues with layout shifts.

I spend some more time on it, and if I use it on everything my layout shits are too much, so decided to only put it on certain elements, and try and define the height of the element.

Collapse
danblack1800 profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Daniel Black • Edited

20/80. 20% of effort constitutes for 80% of the result. Rest 20% of the result require 80% of the effort. Though its just a saying, the general message is at some point efforts are not really worth it. IMO, all that time spent figuring out all the quirks and adjustments for such a small gain would bring more benefit if invested in a more proper direction. Efficiency.

Collapse
dailydevtips1 profile image
Chris Bongers Author

I don't quite get your point about this article, to be honest?
It's a very easy to implement, low impact thing.
Are you saying we should not explore it because it's not a proper direction?

Collapse
yellow1912 profile image
yellow1912

I don't understand the down vote of Daniel's comment. True it looks like it's an easy to implement hack, but there are serious hidden issue with it. The major issue though, is the height of the element you want to set this case property. Without knowing the exact height the browser cannot allocate for it properly and the content will be jumpy. In fact you may run into another issue (layout shift).

With responsive layouts, sometimes it can be challenging to know the exact height before hand so you may create more problems than you solve.

This should be used with care. There are many lower hanging fruits to fix before you try this one out. Definitely 80% effort vs 20% gain.

Thread Thread
dailydevtips1 profile image
Chris Bongers Author

I agree, also not the one who downvoted the comment, I just didn't understand his explanation for where he was going with it.

You are right there are many things one needs to be aware of, but like everything, I try to give a high-level overview of a function, method, or idea.

I don't want to tell you how to exactly do one thing, but yes well mentioned there are some things to consider with this technique.