Back in August 2020, when the content-visiblity
property in CSS trickled its way into Chrome browsers, Una Kravets and Vladimir Levin wrote about it and we covered it. The weirdest part is that to get the performance value out of it, you pair it with contain-intrinsic-size
on these big chunks of the page where you insert some arbitrary guess at a height. I wrote:
That part seems super weird to me. Just guess at a height? What if I’m wrong? Can I hurt performance? Can (or should) I change that value at different viewports if the height difference between small and large screens is drastic?
Jake Archibald and Das Surma just did a video on all this and it helped clarify that a bit. You can see at about 7:30 in just how confusing it is. Jake used this massive HTML spec page as a demo, and made <section>
wrappers around big chunks of HTML, and applied:
section {
content-visibility: auto; /* this is the thing that delays painting */
contain-intrinsic-size: 1px 5000px; /* this is the guess at the height of the content, and also saying width doesn't matter */
}
Apparently that 5000px isn’t the height of the element, it’s the size of the content of that element. I guess that matters because it will push that parent element taller by that number, unless the parent element overrides that with a height of its own. The magic comes from the fact that the browser will only paint¹ the first section (where it’s very likely the viewport isn’t over 5000px tall) and defer the painting on the rest. Sorta like lazy loading, but everything rather than media alone. It assumes the next section is 5000px tall, but once the top of it becomes visible, it will actually get painted and the correct height will be known. So assuming your page is just big ass blocks on top of each other, using an extremely large number should work fine there. Godspeed if your site is more complicated than that, I guess.
It’s a good video and you should watch it:
This is yet another thing where you have to inform the browser about your site so that it can Do Performance Good™. It is information that it can figure out by itself, but not until it has done things that have a performance cost. So you have to tell it up front, allowing it to avoid doing certain types of work. With responsive images, if we give images a srcset
attribute with images and tell the browser in advance how big they are, including a sizes
attribute with information about how our CSS behaves, it can do calculations ahead of time that only download the best possible image. Likewise, with the will-change
property in CSS, we can tell the browser when we’re going to be doing movement ahead of time so it can pre-optimize for that in a way it couldn’t otherwise. It’s understandable, but a little tiresome. It’s like we need a stuff-you-need-to-know.manifest
file to give browsers before it does anything else — only that would be an additional request!
The accessibility implications are important too. Steve Faulkner did a test applying content-visibility: auto
to images and paragraphs:
The content is visually hidden, but in both JAWS and NVDA the hidden
<img>
is announced but the content of the<p>
element is not. This has to do with how theimg
and thep
element content are represented in the browser accessibility tree: Theimg
is exposed in the accessibility tree with thealt
text as the accessible name. The content of thep
element is not present in the accessibility tree.
He notes that content hidden this way should not be available to screen readers, per the spec. I could see it going either way, like hide it all as if it was display: none
, meaning none of it is in the accessibility tree. Or, leave it all in the accessibility tree. Right now it’s a tweener where you might see a bunch of stray images in the accessibility tree without any other context than their alt
text. This is an interesting example of new tech going out with more rough edges than you might like to see.
Speaking of alt
text, we all know those shouldn’t be empty when they represent important content that needs to be described to someone who can’t see them. They should be like paragraphs, says Dave:
I finally made the simplest of all connections:
alt
text is like a paragraph. Word pictures. Basic I know, but it helps me contextualize how to write goodalt
text as well as source order of my code.
I don’t want to be overly negative here! The performance gains for setting up a long-scrolling page with content-visibility
is huge and that’s awesome. Being able to inform the browser about what is OK not to paint in two lines of code is pretty nice.
- I keep saying “paint” but I’m not sure if that’s really the right term or if it means something more specific. The spec says stuff like “allowing user agents to potentially omit large swathes of layout and rendering work until it becomes needed” (emphasis mine).
I disagree with the accessibility part of this article.
If a 3rd party program doesn’t apply the spec correctly, they should fix it instead of dumping the responsibility on the developers.
There seems to be a growing trend of making everything the frontend developer’s responsibility. I wholeheartedly disagree with it.
The biggest culprits of this trend are Apple and Google, 2 companies past the trillion dollars market capitalization.
Smaller companies seems to think it’s ok too because it benefits them. Why fix a problem at the root when you can just shovel it to all the frontend devs?
We’re not profiting from this, they are.
It needs to end and it starts by stopping encouraging these practices in the articles posted…
I was trying out this content-visibility property today and the first thing I noticed is that the scrollbar doesn’t behave correctly anymore. It gets jumpy as the huge content-intrinsic-size doesn’t match the actual size of the sections.
The other problem I noticed is for people who actually grab the scrollbar with the mouse to move up and down a page quickly. There’s a very, very noticeable jankiness on pages using
content-visibility: auto
I’m not sure what the best solution is there. You could use a mutationObserver to set
content-visibility: visible
on each element once it’s in the viewport, but that seems like a hack.If you’re using
content-visibility: auto
on a parent item, the child items get cut off when transforming scale over 1.0. Settingoverflow:visible
doesn’t help in this case.(content-visibility: auto;) create an issue for anchor link smooth scrolling (scroll-behavior: smooth;).
I had also issues with scrollbar and wanted only use
content-visibility
when device is mobile device, because my site doesn’t benefit of this property when using site on computer (already had perfect 100 everytime on PageSpeed Insights) and the scrollbar issue obviously doesn’t happen in mobile.I found out that there actually is decent way to target mobile devices with CSS (without any hacks):
https://css-irl.info/detecting-hover-capable-devices/
So I just put this together with this information:
hover: none
means that targetted device can’t hover element (usually you can’t except some cases in Android) andpointer: coarse
is “the primary input mechanism includes a pointing device of limited accuracy” (quote from MDN).This media query does include those who use touch screen on PC, but those users are super rare that it’s basically nonexisting IMO.
yes with content-visibility:auto causing scrollbar issues and overflow-content is not visible