首頁  >  文章  >  web前端  >  深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

青灯夜游
青灯夜游轉載
2022-07-18 11:19:352737瀏覽

這篇文章帶大家了解CS​​S content-visibility屬性,聊聊使用該屬性怎麼優化渲染效能,希望對大家有幫助!

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

最近在業務中實際使用 content-visibility 進了一些渲染效能的最佳化。

這是一個比較新且有強大功能的屬性。本文將帶領大家深入理解一番。 【推薦學習:css影片教學

何為 content-visibility

content-visibility:屬性控制一個元素是否渲染其內容,它允許使用者代理程式(瀏覽器)潛在地省略大量佈局和渲染工作,直到需要它為止。

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 user agents to potentially omit large swathes of usermit 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.#幾個常見的取值。

/* Keyword values */
content-visibility: visible;
content-visibility: hidden;
content-visibility: auto;
分別解釋:

content-visibility: visible
    :預設值,沒有任何效果,相當於沒有加上
  • content-visibility,元素的渲染與往常一致。 content-visibility: hidden
  • :與
  • display: none 類似,使用者代理程式將跳過其內容的渲染。 (這裡要注意的是,跳過的是內容的渲染)content-visibility: auto
  • :如果該元素不在螢幕上,並且與使用者無關,則不會渲染其後代元素。
  • contain-intrinsic-size

當然,除content-visibility

之外,還有一個與之配套的屬性- -

contain-intrinsic-sizecontain-intrinsic-size

:控制由

content-visibility 指定的元素的自然大小。 上面兩個屬性光看定義和介紹會有點繞。

我們先來看看

content-visibility

如何具體使用。

content-visibility: visible

是預設值,加入後沒有任何效果,我們就直接跳過。

利用

content-visibility: hidden

最佳化展示切換效能首先來看看content-visibility: hidden

,它通常會拿來和

display: none 做比較,但其實它們之間還是有很大的不同的。 首先,假設我們有兩個DIV 包裹框:

<div class="g-wrap">
    <div>1111</div>
    <div class="hidden">2222</div>
</div>

設定兩個div 為

200x200

的黑色區塊:

.g-wrap > div {
    width: 200px;
    height: 200px;
    background: #000;
}
效果如下:

#OK,沒有問題,接下來,我們給其中的深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能.hidden

設定

content-visibility: hidden,看看會發生什麼:

.hidden {
    content-visibility: hidden;
}
效果如下:

注意,仔細看效果,這裡加入了深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能content-visibility: hidden

之後,

消失的只是添加了該元素的div 的子元素消失不見,而父元素本身及其樣式,還是存在頁面上的如果我們去掉設定了content-visibility: hidden

的元素本身的

widthheightpaddingmargin 等屬性,則元素看起來就如同設定了display: none 一般,在頁面上消失不見了。 那麼,content-visibility: hidden

的功能是什麼呢?

設定了 content-visibility: hidden

的元素,

其元素的子元素將會被隱藏,但是,它的渲染狀態將會被快取。所以,當 content-visibility: hidden 被移除時,使用者代理程式不必重頭開始渲染它和它的子元素。 因此,如果我們將這個屬性應用在一些一開始需要被隱藏,但是其後在頁面的某個時刻需要被渲染,或者是一些需要被頻繁切換顯示、隱藏狀態的元素上,其渲染效率將會有一個非常大的提升。

利用

content-visibility: auto

實作虛擬清單#OK,接下來是content-visibility

的核心用法,利用

auto 屬性值。

content-visibility: auto 的作用是,如果该元素不在屏幕上,并且与用户无关,则不会渲染其后代元素。是不是与 LazyLoad 非常类似?

我们来看这样一个 DEMO ,了解其作用:

假设,我们存在这样一个 HTML 结构,含有大量的文本内容:

<div class="g-wrap">
    <div class="paragraph">...</div>
    // ... 包含了 N 个 paragraph
    <div class="paragraph">...</div>
</div>

每个 .paragraph 的内容如下:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

因此,整个的页面看起来就是这样的:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

由于,我们没有对页面内容进行任何处理,因此,所有的 .paragraph 在页面刷新的一瞬间,都会进行渲染,看到的效果就如上所示。

当然,现代浏览器愈加趋于智能,基于这种场景,其实我们非常希望对于仍未看到,仍旧未滚动到的区域,可以延迟加载,只有到我们需要展示、滚动到该处时,页面内容才进行渲染。

基于这种场景,content-visibility: auto 就应运而生了,它允许浏览器对于设置了该属性的元素进行判断,如果该元素当前不处于视口内,则不渲染该元素。

我们基于上述的代码,只需要最小化,添加这样一段代码:

.paragraph {
    content-visibility: auto;
}

再看看效果,仔细观察右侧的滚动条:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

这里我使用了 ::-webkit-scrollbar 相关样式,让滚动条更明显。

可能你还没意识到发生了什么,我们对比下添加了 content-visibility: auto 和没有添加 content-visibility: auto 的两种效果下文本的整体高度:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

有着非常明显的差异,这是因为,设置了 content-visibility: auto 的元素,在非可视区域内,目前并没有被渲染,因此,右侧内容的高度其实是比正常状态下少了一大截的。

好,我们实际开始进行滚动,看看会发生什么:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

由于下方的元素在滚动的过程中,出现在视口范围内才被渲染,因此,滚动条出现了明显的飘忽不定的抖动现象。(当然这也是使用了 content-visibility: auto 的一个小问题之一),不过明显可以看出,这与我们通常使用 JavaScript 实现的虚拟列表非常类似。

当然,在向下滚动的过程中,上方消失的已经被渲染过且消失在视口的元素,也会因为消失在视口中,重新被隐藏。因此,即便页面滚动到最下方,整体的滚动条高度还是没有什么变化的。

content-visibility 是否能够优化渲染性能?

那么,content-visibility 是否能够优化渲染性能呢?

Youtube -- Slashing layout cost with content-visibility 中,给了一个非常好的例子。

这里我简单复现一下。

对于一个存在巨量 HTML 内容的页面,譬如类似于这个页面 -- HTML - Living Standard

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

可以感受到,往下翻,根本翻不到尽头。(这里我在本地模拟了该页面,复制了该页面的所有 DOM,并非实际在该网站进行测试)

如果不对这个页面做任何处理,看看首次渲染需要花费的时间:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

可以看到,DOMContentLoaded 的时间的 3s+,而花费在 Rendering 上的就有整整 2900ms

而如果给这个页面的每个段落,添加上 content-visibility: auto,再看看整体的耗时:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

可以看到,DOMContentLoaded 的时间骤降至了 500ms+,而花费在 Rendering 上的,直接优化到了 61ms

2900ms --> 61ms,可谓是惊人级别的优化了。因此,content-visibility: auto 对于长文本、长列表功能的优化是显而易见的。

利用 contain-intrinsic-size 解决滚动条抖动问题

当然,content-visibility 也存在一些小问题。

从上面的例子,也能看到,在利用 content-visibility: auto 处理长文本、长列表的时候。在滚动页面的过程中,滚动条一直在抖动,这不是一个很好的体验。

当然,这也是许多虚拟列表都会存在的一些问题。

好在,规范制定者也发现了这个问题。这里我们可以使用另外一个 CSS 属性,也就是文章一开头提到的另外一个属性 -- contain-intrinsic-size,来解决这个问题。

contain-intrinsic-size:控制由 content-visibility 指定的元素的自然大小。

什么意思呢?

还是上面的例子

<div class="g-wrap">
    <div class="paragraph">...</div>
    // ... 包含了 N 个 paragraph
    <div class="paragraph">...</div>
</div>

如果我们不使用 contain-intrinsic-size,只对视口之外的元素使用 content-visibility: auto,那么视口外的元素高度通常就为 0。

当然,如果直接给父元素设置固定的 height,也是会有高度的。

那么实际的滚动效果,滚动条就是抖动的:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

所以,我们可以同时利用上 contain-intrinsic-size,如果能准确知道设置了 content-visibility: auto 的元素在渲染状态下的高度,就填写对应的高度。如果如法准确知道高度,也可以填写一个大概的值:

.paragraph {
    content-visibility: auto;
    contain-intrinsic-size: 320px;
}

如此之后,浏览器会给未被实际渲染的视口之外的 .paragraph 元素一个高度,避免出现滚动条抖动的现象:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

你可以自己亲自尝试感受一下:CodePen Demo -- content-visibility: auto Demo

content-visibility: auto VS LazyLoad

那么,content-visibility: auto 是否可以替代 LazyLoad(懒加载)呢?

我们来看看我们通常对于 LazyLoad(懒加载)的一个定义。

LazyLoad:通常而言,LazyLoad 的作用在于,当页面未滚动到相应区域,该区域内的资源(网络请求)不会被加载。反之,当页面滚动到相应区域,相关资源的请求才会被发起。

那么,如果 content-visibility: auto 要能够替代 LazyLoad,则需要做到,初始化渲染的时候,在页面当前展示范围外的,设定了 content-visibility: auto 的元素内的一些静态资源不会被加载。

这里我尝试做了一个简单的 DEMO:

还是借助上述的代码,假设我们有如下的 HTML 结构,也就是在上述代码基础上,插入一些图片资源:

<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" alt="深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能" >
    </div>
    <div class="g-img">
      <img  src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTD8kEsEE3hJ64aU-_TKQJtvKDtTOGQfT3A4A&usqp=CAU" alt="深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能" >
    </div>
    <div class="g-img">
      <img  src="https://i.pinimg.com/originals/e8/ba/25/e8ba252917952f23dfc9715e942e654e.jpg" alt="深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能" >
    </div>
</div>

相应设置下 CSS:

.paragraph,
.g-img {
    content-visibility: auto;
}

当刷新页面的时候,观察网络请求(Network)的状况:

1深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

即便当前页面可视区域外的内容未被渲染,但是图片依然会被加载!

因此,这也得到了一个非常重要的结论:

content-visibility: auto 无法直接替代 LazyLoad,设置了 content-visibility: auto 的元素在可视区外只是未被渲染,但是其中的静态资源仍旧会在页面初始化的时候被全部加载

所以,在实际使用中,如果你的业务中已经使用了比较完善的 Lazyload 处理长列表或者一些图片资源,那么 content-visibility: auto 不是更好的选择。

可访问性功能探究

当然,content-visibility: auto 的特性又引申出了另外一个有意思的点。

如果说可视区外的内容未被渲染,那是否会影响用户进行全文检索呢?毕竟这是一个非常重要的功能。

我们再来做个探究,还是上面的 DEMO,我们在首尾添加两个特殊的字符串:

<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>

相应设置下 CSS:

.paragraph,
.text {
    content-visibility: auto;
}

好,如此一来,在页面刷新后,第二个 .text 是处于未被渲染状态,我们试着全局 ctrl + F 查找一下,看看能找到几个:

深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

很有趣的現象,全域尋找的時候,可以找到目前未被渲染的元素內的內容。

這裡,我們可以得到另一個非常重要的點:

即使存在設定了content-visibility: auto 的未被渲染的元素,但是它並不會影響全域的搜尋功能

這也是content-visibility 設計上充分的考慮,對可訪問性功能,或者說使用者體驗的考量,有了這一點,對於它的實際使用有非常大的幫助。

content-visibility 的一些其他問題

#首先,看看content-visibility 的兼容性(2022- 06-03):

1深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能

目前還是比較慘淡的,並且我沒有實際在業務中使用它,需要再等待一段時間。當然,由於此屬性屬於漸進增強一類的功能,即便失效,也完全不影響頁面本身的展示。

同時,也有一些同學表示,利用 content-visibility: auto 只能解決部分場景,在海量 DOM 的場景下的實際效果,還有待進一步的實測。真正運用的時候,多做對比,在做取捨。

當然,現代瀏覽器已經越來越智能,類似content-visibility 功能的屬性也越來越多,我們在效能最佳化的路上有了更多選擇,總歸是一件好事。

總結一下

再簡單總結一下:

  • #在一些需要被頻繁切換顯示、隱藏狀態的元素上,使用content-visibility: hidden,使用者代理程式無需重頭開始渲染它和它的子元素,能有效的提升切換時的渲染效能;

  • content-visibility: auto 的作用更類似於虛擬列表,使用它能極大的提升長列表、長文本頁的渲染性能;

  • 合理使用contain-intrinsic-size 預估設定了content-visibility: auto 元素的高寬,可以有效的避免滾動條在滾動過程中的抖動;

  • #content-visibility: auto 無法直接取代LazyLoad,設定了content-visibility: auto 的元素在視覺區外只是未被渲染,但是其中的靜態資源仍舊會在頁面初始化的時候被全部載入;

  • 即使存在設定了content-visibility: auto 的未被渲染的元素,但是它並不會影響全域的搜尋功能。

(學習影片分享:web前端入門

以上是深入了解content-visibility屬性,聊聊怎麼用它來優化渲染效能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:cnblogs.com。如有侵權,請聯絡admin@php.cn刪除