首頁 > web前端 > css教學 > 聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

青灯夜游
發布: 2022-11-22 20:16:14
轉載
2999 人瀏覽過

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

對於前端人員來講,最令人頭疼的應該就是頁面性能了,當用戶在訪問一個頁面時,總是希望它能夠快速呈現在眼前並且是可交互狀態。如果頁面載入過慢,你的使用者很可能會因此離開你而去。所以頁面效能對於前端開發者來說可謂是重中之重,其實你如果了解頁面從載入到渲染完成的整個過程,就知道應該從哪方面下手了。

嗯,不要偏離了,今天我們主要來研究長列表頁面的渲染性能

現如今的頁面越來越複雜,一個頁面往往承載著大量的元素,最常見的就是一些電商頁面,數以萬計的商品列表是怎麼保證渲染不卡頓的,大家在面對這種長列表渲染的場景下,一般都會採用分頁或者虛擬列表來減緩頁面一次性渲染的壓力,但這些方式都需要配合JS來時實現,那麼有沒有僅使用CSS就能夠實現的方案呢?

答案是有的,它就是我們今天的主角 —— 內容可見性(content-visibility)。 【推薦學習:css影片教學

content-visibility

##屬性值

content-visibility是CSS新增的屬性,主要用來提高頁面渲染效能,它可以控制一個元素是否渲染其內容,並且允許瀏覽器跳過這些元素的佈局與渲染。

    visible:預設值,沒有效果。元素的內容被正常佈局和呈現。
  • hidden:元素跳過它的內容。跳過的內容不能被使用者代理功能訪問,例如在頁面中尋找、標籤順序導航等,也不能被選擇或聚焦。這類似於給內容設定
  • display: none
  • auto:此元素開啟佈局包含、樣式包含和繪製包含。如果該元素與使用者不相關,它也會跳過其內容。與 hidden 不同,跳過的內容必須仍可正常用於使用者代理功能,例如在頁面中查找、tab 順序導航等,並且必須正常可聚焦和可選擇。

content-visibility: hidden手動管理可見性

#上面說到

content-visibility: hidden的效果與 display: none類似,但其實兩者還是有比較大的區別的:

    #content-visibility: hidden 只是隱藏了子元素,自身不會被隱藏
  • #content-visibility: hidden 隱藏內容的渲染狀態會被緩存,所以當它被移除或設定為可見時,瀏覽器不會重新渲染,而是會套用緩存,所以對於需要頻繁切換顯示隱藏的元素,這個屬性能夠大幅提升渲染效能。

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

從這上面我們可以看到,加入了

content-visibility: hidden元素的子元素確實是沒有渲染,但它自身是會渲染的!

content-visibility: auto 跳過渲染工作

我們仔細想想,頁面上雖然會有很多元素,但是它們會同時呈現在使用者眼前嗎,很顯然是不會的,用戶每次能夠真實看到就只有設備可見區那些內容,對於非可見區的內容只要頁面不發生滾動,用戶就永遠看不到。雖然使用者看不到,但瀏覽器卻會實實在在的去渲染,以至於浪費大量的效能。所以我們得想辦法讓瀏覽器不渲染非視覺區的內容就能夠達到提升頁面渲染效能的效果。

我們上面說到的虛擬列表原理其實就跟這個類似,在首屏加載時,只加載

可視區的內容,當頁面發生滾動時,動態通過計算獲得視覺區的內容,並將非視覺區的內容進行刪除,這樣就能夠大幅提升長列表的渲染效能。

但這個需要配合JS才能實現,現在我們可以使用CSS中

content-visibility: auto,它可以用來跳過螢幕外的內容渲染,對於這種有大量離螢幕內容的長列表,可以大幅減少頁面渲染時間。

我們將上面的例子稍微改改:

<template>
  <div>
    <div>
      <img  :src="book.bookCover" / alt="聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能" >
      <div>
        <div>{{ `${book.bookName}${index + 1}` }}</div>
        <div>{{ book.catlog }}</div>
        <div>
          <div v-for="(item, index) in book.tags" :key="index">
            {{ item }}
          </div>
        </div>
        <div>
          {{ book.desc }}
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { toRefs } from "vue";

const props = defineProps<{
  book: any;
  index: any;
}>();
const { book, index } = toRefs(props);
</script>

<style scoped>
.card_item {
  margin: 20px auto;
  content-visibility: auto;
}
  / *
  ...
  */
</style>
登入後複製

首先是沒有加入

content-visibility: auto的效果,無論這些元素是否在視覺區,都會被渲染

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

如果我們在平常業務中這樣寫,用戶進入到這個頁面可能就直接口吐芬芳了,為了性能考慮,我們為每一個列表項加上:

.card_item {
  content-visibility: auto;
}
登入後複製

這時候我們再來看下效果:

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

从第10个开始,这些没在可视区的元素就没有被渲染,这可比上面那种全部元素都渲染好太多了,但是如果浏览器不渲染页面内的一些元素,滚动将是一场噩梦,因为无法正确计算页面高度。这是因为,content-visibility会将分配给它的元素的高度(height)视为0,浏览器在渲染之前会将这个元素的高度变为0,从而使我们的页面高度和滚动变得混乱。

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

这里我们可以看到页面上的滚动条会出现抖动现象,这是因为可视区外的元素只有出现在了可视区才会被渲染,这就回导致前后页面高度会发生变化,从而出现滚动条的诡异抖动现象,这是虚拟列表基本都会存在的问题。

⚠️注意:当元素接近视口时,浏览器不再添加size容器并开始绘制和命中测试元素的内容。这使得渲染工作能够及时完成以供用户查看。

这也是为什么上面我们看到的是从第十个才开始不渲染子元素,因为它需要一个缓冲区以便浏览器能够在页面发生滚动时及时渲染呈现在用户眼前。

上面提到的size其实是一种 CSS 属性的潜在值contain,它指的是元素上的大小限制确保元素的框可以在不需要检查其后代的情况下进行布局。这意味着如果我们只需要元素的大小,我们可以跳过后代的布局。

contain-intrinsic-size 救场

页面在滚动过程中滚动条一直抖动,这是一个不能接受的体验问题,为了更好地实现content-visibility,浏览器需要应用 size containment 以确保内容的渲染结果不会以任何方式影响元素的大小。这意味着该元素将像空的一样布局。如果元素没有在常规块布局中指定的高度,那么它将是 0 高度。

这个时候我们可以使用contain-intrinsic-size来指定的元素自然大小,确保我们未渲染子元素的 div 仍然占据空间,同时也保留延迟渲染的好处。

语法

此属性是以下 CSS 属性的简写:

  • contain-intrinsic-width
  • contain-intrinsic-height
/* Keyword values */
contain-intrinsic-width: none;

/* <length> values */
contain-intrinsic-size: 1000px;
contain-intrinsic-size: 10rem;

/* width | height */
contain-intrinsic-size: 1000px 1.5em;

/* auto <length> */
contain-intrinsic-size: auto 300px;

/* auto width | auto height */
contain-intrinsic-size: auto 300px auto 4rem;
登入後複製

contain-intrinsic-size 可以为元素指定以下一个或两个值。如果指定了两个值,则第一个值适用于宽度,第二个值适用于高度。如果指定单个值,则它适用于宽度和高度。

实现

我们只需要给添加了content-visibility: auto的元素添加上contain-intrinsic-size就能够解决滚动条抖动的问题,当然,这个高度约接近真实渲染的高度,效果会越好,如果实在无法知道准确的高度,我们也可以给一个大概的值,也会使滚动条的问题相对减少。

.card_item {
  content-visibility: auto;
  contain-intrinsic-size: 200px;
}
登入後複製

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

之前没添加contain-intrinsic-size属性时,可视区外的元素高度都是0,现在这些元素高度都是我们设置的contain-intrinsic-size的值,这样的话整个页面的高度就是不会发生变化(或者说变化很小),从而页面滚动条也不会出现抖动问题(或者说抖动减少)

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

性能对比

上面说了这么多,content-visibility是否真的能够提高页面的渲染性能呢,我们来实际对比看看:

  • 首先是没有content-visibility的页面渲染

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

  • 然后是有content-visibility的页面渲染

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

上面是用1000个列表元素进行测试的,有content-visibility的页面渲染花费时间大概是37ms,而没有content-visibility的页面渲染花费时间大概是269ms,提升了足足有7倍之多!!!

对于列表元素更多的页面,content-visibility带来的渲染性能提升会更加明显。

思考?

能否减小页面的内存占用?

之前有同学问到了content-visibility: auto是否会减少页面内存的占用,这个我们可以查看下使用前后页面所占用内存的大小是否有变化。

我们可以通过chrome浏览器 设置 --> 更多工具 --> 任务管理器 查看页面占用内存大小。

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

  • 首先是没有content-visibility: auto,页面占用内存大概为96.2MB

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

  • 然后是添加了content-visibility: auto,页面占用内存仍然是96.2MB

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

也就是说,它并不会减少页面占用内存大小,这些元素是真实存在于DOM树中的,并且我们也可以通过JS访问到

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

是否会影响脚本的加载行为?

如果我们在添加了content-visibility: auto的元素内去加载脚本,并且此时的元素处于一个不可见的状态,那么此时元素内的脚本能够正常加载呢?

<!-- ... 第十二个 -->
<div class="visibility_item">
        <div class="inner">
            测试脚本
            <img src="../../../../images/22-11/聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能" alt="">
            <script src="./2.js"></script>
        </div>
        
</div>
登入後複製

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

很明显它并不会影响脚本与图片的加载行为,并且脚本再加载后能够正常执行。结合上面第一点,我们可以得出结论,使用了content-visibility: auto的元素影响的只是子元素的渲染,对于内部静态资源的加载还是正常进行。

但我们需要注意的是脚本的执行时机,如果要获取DOM元素的话,此时的脚本只能获取到它加载位置之前的DOM元素,而与它自身DOM有没有渲染无关!

// 2.js
console.log(&#39;测试脚本&#39;)
console.log(&#39;第十一个&#39;, document.querySelectorAll(&#39;.visibility_item&#39;)[10])

console.log(&#39;第十三个&#39;, document.querySelectorAll(&#39;.visibility_item&#39;)[12])
登入後複製

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

可访问性

使用了content-visibility: auto并且在非可视区的元素是否存在于可访问树中?

聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

这里我们可以看出content-visibility: auto是屏幕外的内容在文档对象模型中仍然可用,因此在可访问性树中(与visibility: hidden不同)。这意味着我们可以在页面上搜索并导航到该内容,而无需等待它加载或牺牲渲染性能。

这个功能特性是在chrome 90 中更新的,在 chrome 85-89 中,屏幕外的子元素content-visibility: auto被标记为不可见。

兼容性

content-visibility是chrome85新增的特性,所以兼容性还不是很高,但它是一个非常实用的CSS属性,由于跳过了渲染,如果我们大部分内容都在屏幕外,利用该content-visibility属性可以使初始用户加载速度更快。相信兼容性的问题在不久的将来会得到解决~聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能

原文地址:https://juejin.cn/post/7168629736838463525

(学习视频分享:web前端

以上是聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
css
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板