Recently used in business content-visibility
some rendering performance optimizations have been made.
This is a relatively new and powerful property. This article will lead you to a deeper understanding.
What is content-visibility
?
content-visibility
: attribute controls whether an element renders its content, it allows user agents (browser) to potentially omit a lot of layout and rendering work until it is needed.
Original MDN: The content-visibility CSS property controls whether or not an element renders its contents at all, along with forcing a strong set of containments, allowing user agents to potentially omit large swathes of layout and rendering work until it becomes needed. Basically it enables the user agent to skip an element's rendering work (including layout and painting) until it is needed — which makes the initial page load much faster.
It has several common values.
/* Keyword values */
content-visibility: visible;
content-visibility: hidden;
content-visibility: auto;
Explain separately:
-
content-visibility: visible
: Default value, no effect, equivalent to no addition ofcontent-visibility
, the rendering of elements is the same as usual. -
content-visibility: hidden
: Similar todisplay: none
, the user agent will skip rendering of its content. (It should be noted here that what is skipped is the rendering of the content) -
content-visibility: auto
: If the element is off-screen and not relevant to the user, its descendant elements will not be rendered.
contain-intrinsic-size
Of course, in addition to content-visibility
, there is a matching attribute contain-intrinsic-size
.
contain-intrinsic-size
: Controls the natural size of the element specified by content-visibility
.
The above two attributes will be a bit confusing just looking at the definition and introduction.
Let's first take a look at content-visibility
how to use it specifically.
content-visibility: visible
is the default value. After adding it, there is no effect, so we just skip it.
Use content-visibility: hidden
to optimize display switching performance
First, let's take a look at content-visibility: hidden
, which is usually compared with display: none
, but there are still big differences between them.
First, let's say we have two DIV wrappers:
<div class="g-wrap">
<div>1111</div>
<div class="hidden">2222</div>
</div>
Set two divs as black blocks of 200x200
:
.g-wrap > div {
width: 200px;
height: 200px;
background: #000;
}
The effect is as follows:
OK, no problem, next, we set ---5503e9dac60b6c5aa6f541fc4377ef39 .hidden
to content-visibility: hidden
and see what happens:
.hidden {
content-visibility: hidden;
}
The effect is as follows:
Note that after looking at the effect carefully, after adding content-visibility: hidden
, only the child element of the div to which the element was added disappears, and the parent element itself and its styles still exist on the page .
content-visibility: hidden
设置了---62f1feb4a3766b820e0ca72fc70d13da---的元素本身的width
、 height
、 padding
、 margin
, The element looks as if it was set display: none
and disappears from the page.
So, what does content-visibility: hidden
do?
For an element with content-visibility: hidden
set, its children will be hidden, but its rendering state will be cached . So, when content-visibility: hidden
is removed, the user agent doesn't need to start over to render it and its children.
Therefore, if we apply this attribute to some elements that need to be hidden at the beginning, but then need to be rendered at a certain point in the page, or some elements that need to be switched between display and hidden states frequently, the rendering efficiency will be improved. A very big improvement.
Use content-visibility: auto
to implement a virtual list
OK, next is the core usage of ---602ae21d19e42dbadef50d1cdc58d7ac content-visibility
, using the auto
attribute value.
content-visibility: auto
does is that if the element is offscreen and not relevant to the user, its descendant elements will not be rendered. Is it very similar to LazyLoad?
Let's take a look at such a DEMO to understand what it does:
Suppose we have an HTML structure with a lot of text content:
<div class="g-wrap">
<div class="paragraph">...</div>
// ... 包含了 N 个 paragraph
<div class="paragraph">...</div>
</div>
The contents of each .paragraph
are as follows:
So the whole page looks like this:
Since we haven't done any processing on the page content, all of them .paragraph
will be rendered at the moment when the page is refreshed, and the effect is as shown above.
Of course, modern browsers are becoming more and more intelligent. Based on this scenario, we really hope that the area that has not yet been seen and still has not been scrolled to can be loaded lazily. Only when we need to display and scroll there, the content of the page will be displayed. just render.
Based on this scenario, content-visibility: auto
came into being, which allows the browser to judge the element with this attribute set, and if the element is not currently in the viewport, the element is not rendered.
Based on the above code, we only need to minimize and add this piece of code:
.paragraph {
content-visibility: auto;
}
Take a look at the effect again, and carefully observe the scroll bar on the right:
Here I use the ::-webkit-scrollbar
related style to make the scrollbar more obvious.
Maybe you didn't realize what happened, we added content-visibility: auto
and did not add content-visibility: auto
The overall height of the text under the two effects:
There is a very obvious difference. This is because the element that has set content-visibility: auto
is not currently rendered in the non-visual area. Therefore, the height of the content on the right is actually less than in the normal state. A big chunk.
OK, let's actually start rolling and see what happens:
Since the element below is rendered within the viewport range during the scrolling process, the scroll bar exhibits obvious erratic jitter. (Of course this is one of the minor issues with using content-visibility: auto
), but it's obvious that this is very similar to the virtual lists we usually implement with JavaScript.
Of course, in the process of scrolling down, the elements that have been rendered and disappeared from the viewport above will also be hidden again because they disappear from the viewport. Therefore, even if the page is scrolled to the bottom, the overall scroll bar height does not change.
content-visibility
it possible to optimize rendering performance?
So, does content-visibility
optimize rendering performance?
In Youtube -- Slashing layout cost with content-visibility , a very good example is given.
Here I simply reproduce it.
For a page with huge HTML content, such as this page -- HTML - Living Standard
You can feel that when you turn down, you can't turn to the end at all. (Here I simulate the page locally, copying all the DOM of the page, not actually testing on the website)
If you don't do anything with this page, take a look at the time it takes to render the first time:
It can be seen that the time spent on DOMContentLoaded is 3s+
, and the time spent on Rendering is exactly 2900ms
!
And if you add content-visibility: auto
to each paragraph of this page, and then look at the overall time consumption:
It can be seen that the time of DOMContentLoaded has dropped sharply to 500ms+
, and the time spent on Rendering is directly optimized to 61ms
!
2900ms --> 61ms, which is an amazing level of optimization. Therefore, content-visibility: auto
optimization for long text, long list functions is obvious.
Use contain-intrinsic-size
to solve the problem of scroll bar jitter
Of course, content-visibility
also has some minor problems.
From the above example, it can also be seen that when using content-visibility: auto
to process long text and long lists. While scrolling the page, the scroll bar keeps shaking, which is not a good experience.
Of course, this is also a problem with many virtual lists.
Fortunately, the norm-setters have also discovered this problem. Here we can use another CSS property, which is another property mentioned at the beginning of the article contain-intrinsic-size
, to solve this problem.
contain-intrinsic-size
: Controls the natural size of the element specified by content-visibility
.
What does that mean?
or the above example
<div class="g-wrap">
<div class="paragraph">...</div>
// ... 包含了 N 个 paragraph
<div class="paragraph">...</div>
</div>
If we don't use contain-intrinsic-size
and only use content-visibility: auto
for elements outside the viewport, then the height of elements outside the viewport is usually 0.
Of course, if you directly set a fixed height
to the parent element, there will also be a height.
Then the actual scrolling effect, the scroll bar is shaking:
Therefore, we can use the above contain-intrinsic-size
at the same time. If we can accurately know the height of the element that has set content-visibility: auto
in the rendering state, fill in the corresponding height. If you can accurately know the height, you can also fill in an approximate value:
.paragraph {
content-visibility: auto;
contain-intrinsic-size: 320px;
}
After this, the browser will give a height to the .paragraph
element outside the viewport that is not actually rendered to avoid the phenomenon of scroll bar jitter:
You can try it yourself: CodePen Demo -- content-visibility: auto Demo
content-visibility: auto
VS LazyLoad
So, can content-visibility: auto
replace LazyLoad?
Let's take a look at our usual definition of LazyLoad.
LazyLoad : Generally speaking, the role of LazyLoad is that when the page is not scrolled to the corresponding area, the resources (network requests) in this area will not be loaded. On the contrary, when the page scrolls to the corresponding area, the request for the relevant resource will be initiated.
Then, if content-visibility: auto
can replace LazyLoad, you need to do, when initializing rendering, set some static resources in the element of content-visibility: auto
outside the current display range of the page will not be loaded.
Here I try to make a simple demo:
Or with the help of the above code, suppose we have the following HTML structure, that is, on the basis of the above code, insert some image resources:
<div class="g-wrap">
<div class="paragraph">...</div>
// ... 包含了 N 个 paragraph
<div class="paragraph">...</div>
<div class="g-img">
<img src="https://www.womenly.net/wp-content/uploads/2017/03/Tips-to-Maintain-the-Soft-Skin.jpg">
</div>
<div class="g-img">
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTD8kEsEE3hJ64aU-_TKQJtvKDtTOGQfT3A4A&usqp=CAU">
</div>
<div class="g-img">
<img src="https://i.pinimg.com/originals/e8/ba/25/e8ba252917952f23dfc9715e942e654e.jpg">
</div>
</div>
Set the CSS accordingly:
.paragraph,
.g-img {
content-visibility: auto;
}
When refreshing the page, observe the status of the network request (Network):
Even if the content outside the visible area of the current page is not rendered, the image will still be loaded!
So this also leads to a very important conclusion:
content-visibility: auto
Cannot directly replace LazyLoad, the element with content-visibility: auto
is just not rendered outside the visible area, but the static resources in it will still be fully loaded when the page is initialized .
Therefore, in actual use, if your business has already used a relatively complete Lazyload to process long lists or some image resources, then content-visibility: auto
is not a better choice.
Accessibility feature exploration
Of course, the feature of content-visibility: auto
brings out another interesting point.
If the content outside the visible area is not rendered, will it affect the user's full-text search? It's a very important feature after all.
Let's do another exploration, or the above DEMO, we add two special strings at the beginning and end:
<div class="g-wrap">
<div class="text">
<p>content-visibility: auto 对搜索功能影响的探究</p>
</div>
<div class="paragraph">...</div>
// ... 包含了 N 个 paragraph
<div class="paragraph">...</div>
<div class="text">
<p>content-visibility: auto 对搜索功能影响的探究</p>
</div>
</div>
Set the CSS accordingly:
.paragraph,
.text {
content-visibility: auto;
}
Ok, so, after the page is refreshed, the second one .text
is in an unrendered state. Let's try the global ctrl + F
look it up and see how many you can find:
It's an interesting phenomenon. When searching globally, you can find the content of elements that are not currently rendered.
Here, we can get another very important point:
Even if there is an unrendered element with the setting content-visibility: auto
it does not affect the global search function .
This is also content-visibility
the design is fully considered, and the accessibility function, or the consideration of user experience, with this, it is very helpful for its actual use.
Some other issues with content-visibility
First, look at the compatibility of content-visibility
(2022-06-03):
It's still pretty bleak right now, and I haven't actually used it in business, and will have to wait a bit longer. Of course, since this attribute is a function of progressive enhancement, even if it fails, it will not affect the display of the page itself at all.
At the same time, some students said that the use of content-visibility: auto
can only solve some scenarios, and the actual effect in the scenario of massive DOM needs further actual measurement. When actually using it, make more comparisons and make trade-offs.
Of course, modern browsers have become more and more intelligent, and there are more and more attributes similar to content-visibility
. We have more choices on the road of performance optimization, which is always a good thing.
in conclusion
To briefly summarize:
- On some elements that need to be switched between display and hidden states frequently, using
content-visibility: hidden
, the user agent does not need to re-render it and its sub-elements, which can effectively improve the rendering performance during switching; -
content-visibility: auto
is more similar to the virtual list, using it can greatly improve the rendering performance of long list and long text pages; - Reasonable use of
contain-intrinsic-size
is estimated to setcontent-visibility: auto
the height and width of the element, which can effectively avoid the jitter of the scroll bar during the scrolling process; -
content-visibility: auto
Cannot directly replace LazyLoad, the element withcontent-visibility: auto
is just not rendered outside the visible area, but the static resources in it will still be fully loaded when the page is initialized; - Even if there is an unrendered element with the setting
content-visibility: auto
, it does not affect the global search function.
at last
This concludes this article, I hope it helps you :)
If you want to get the most interesting CSS information, don't miss my official account -- iCSS front-end anecdotes 😄
More wonderful CSS technical articles are summarized in my Github -- iCSS , which will be updated continuously. Welcome to click star to subscribe to the collection.
If you have any questions or suggestions, you can communicate more. Original articles are limited in writing and knowledge. If there are any inaccuracies in the article, please let me know.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。