14
头图

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 of content-visibility , the rendering of elements is the same as usual.
  • content-visibility: hidden : Similar to display: 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---的元素本身的widthheightpaddingmargin , 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:

  1. 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;
  2. 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;
  3. Reasonable use of contain-intrinsic-size is estimated to set content-visibility: auto the height and width of the element, which can effectively avoid the jitter of the scroll bar during the scrolling process;
  4. 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;
  5. 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.


chokcoco
12.3k 声望18.5k 粉丝