對於前端人員來講,最令人頭疼的應該就是頁面性能了,當用戶在訪問一個頁面時,總是希望它能夠快速呈現在眼前並且是可交互狀態。如果頁面載入過慢,你的使用者很可能會因此離開你而去。所以頁面效能對於前端開發者來說可謂是重中之重,其實你如果了解頁面從載入到渲染完成的整個過程,就知道應該從哪方面下手了。
嗯,不要偏離了,今天我們主要來研究長列表頁面的渲染性能
現如今的頁面越來越複雜,一個頁面往往承載著大量的元素,最常見的就是一些電商頁面,數以萬計的商品列表是怎麼保證渲染不卡頓的,大家在面對這種長列表渲染的場景下,一般都會採用分頁或者虛擬列表來減緩頁面一次性渲染的壓力,但這些方式都需要配合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 隱藏內容的渲染狀態會被緩存,所以當它被移除或設定為可見時,瀏覽器不會重新渲染,而是會套用緩存,所以對於需要頻繁切換顯示隱藏的元素,這個屬性能夠大幅提升渲染效能。
content-visibility: hidden元素的子元素確實是沒有渲染,但它自身是會渲染的!
content-visibility: auto 跳過渲染工作
我們仔細想想,頁面上雖然會有很多元素,但是它們會同時呈現在使用者眼前嗎,很顯然是不會的,用戶每次能夠真實看到就只有設備可見區那些內容,對於非可見區的內容只要頁面不發生滾動,用戶就永遠看不到。雖然使用者看不到,但瀏覽器卻會實實在在的去渲染,以至於浪費大量的效能。所以我們得想辦法讓瀏覽器不渲染非視覺區的內容就能夠達到提升頁面渲染效能的效果。 我們上面說到的虛擬列表原理其實就跟這個類似,在首屏加載時,只加載可視區的內容,當頁面發生滾動時,動態通過計算獲得
視覺區的內容,並將
非視覺區的內容進行刪除,這樣就能夠大幅提升長列表的渲染效能。
content-visibility: auto,它可以用來跳過螢幕外的內容渲染,對於這種有大量離螢幕內容的長列表,可以大幅減少頁面渲染時間。
<template> <div> <div> <img src="/static/imghwm/default1.png" data-src="book.bookCover" class="lazy" : / 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的效果,無論這些元素是否在視覺區,都會被渲染
.card_item { content-visibility: auto; }這時候我們再來看下效果:
从第10个开始,这些没在可视区的元素就没有被渲染,这可比上面那种全部元素都渲染好太多了,但是如果浏览器不渲染页面内的一些元素,滚动将是一场噩梦,因为无法正确计算页面高度。这是因为,content-visibility
会将分配给它的元素的高度(height
)视为0
,浏览器在渲染之前会将这个元素的高度变为0
,从而使我们的页面高度和滚动变得混乱。
这里我们可以看到页面上的滚动条会出现抖动现象,这是因为可视区外的元素只有出现在了可视区才会被渲染,这就回导致前后页面高度会发生变化,从而出现滚动条的诡异抖动现象,这是虚拟列表基本都会存在的问题。
⚠️注意:当元素接近视口时,浏览器不再添加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; }
之前没添加contain-intrinsic-size
属性时,可视区外的元素高度都是0,现在这些元素高度都是我们设置的contain-intrinsic-size
的值,这样的话整个页面的高度就是不会发生变化(或者说变化很小),从而页面滚动条也不会出现抖动问题(或者说抖动减少)
性能对比
上面说了这么多,content-visibility
是否真的能够提高页面的渲染性能呢,我们来实际对比看看:
- 首先是没有
content-visibility
的页面渲染
- 然后是有
content-visibility
的页面渲染
上面是用1000个列表元素进行测试的,有content-visibility
的页面渲染花费时间大概是37ms,而没有content-visibility
的页面渲染花费时间大概是269ms,提升了足足有7倍之多!!!
对于列表元素更多的页面,content-visibility
带来的渲染性能提升会更加明显。
思考?
能否减小页面的内存占用?
之前有同学问到了content-visibility: auto
是否会减少页面内存的占用,这个我们可以查看下使用前后页面所占用内存的大小是否有变化。
我们可以通过chrome浏览器 设置 --> 更多工具 --> 任务管理器
查看页面占用内存大小。
- 首先是没有
content-visibility: auto
,页面占用内存大概为96.2MB
- 然后是添加了
content-visibility: auto
,页面占用内存仍然是96.2MB
也就是说,它并不会减少页面占用内存大小,这些元素是真实存在于DOM树中的,并且我们也可以通过JS访问到
是否会影响脚本的加载行为?
如果我们在添加了content-visibility: auto
的元素内去加载脚本,并且此时的元素处于一个不可见的状态,那么此时元素内的脚本能够正常加载呢?
<!-- ... 第十二个 --> <div class="visibility_item"> <div class="inner"> 测试脚本 <img src="/static/imghwm/default1.png" data-src="../../../../images/22-11/聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能" class="lazy" alt=""> <script src="./2.js"></script> </div> </div>
很明显它并不会影响脚本与图片的加载行为,并且脚本再加载后能够正常执行。结合上面第一点,我们可以得出结论,使用了content-visibility: auto
的元素影响的只是子元素的渲染,对于内部静态资源的加载还是正常进行。
但我们需要注意的是脚本的执行时机,如果要获取DOM元素的话,此时的脚本只能获取到它加载位置之前的DOM元素,而与它自身DOM有没有渲染无关!
// 2.js console.log('测试脚本') console.log('第十一个', document.querySelectorAll('.visibility_item')[10]) console.log('第十三个', document.querySelectorAll('.visibility_item')[12])
可访问性
使用了content-visibility: auto
并且在非可视区的元素是否存在于可访问树中?
这里我们可以看出content-visibility: auto
是屏幕外的内容在文档对象模型中仍然可用,因此在可访问性树中(与visibility: hidden
不同)。这意味着我们可以在页面上搜索并导航到该内容,而无需等待它加载或牺牲渲染性能。
这个功能特性是在chrome 90 中更新的,在 chrome 85-89 中,屏幕外的子元素content-visibility: auto
被标记为不可见。
兼容性
content-visibility是chrome85新增的特性,所以兼容性还不是很高,但它是一个非常实用的CSS属性,由于跳过了渲染,如果我们大部分内容都在屏幕外,利用该content-visibility
属性可以使初始用户加载速度更快。相信兼容性的问题在不久的将来会得到解决~
原文地址:https://juejin.cn/post/7168629736838463525
(学习视频分享:web前端)
以上是聊聊CSS新特性content-visibility,幫助你提升頁面渲染效能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

您是否曾經在項目上需要一個倒計時計時器?對於這樣的東西,可以自然訪問插件,但實際上更多


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版
SublimeText3 Linux最新版

WebStorm Mac版
好用的JavaScript開發工具

禪工作室 13.0.1
強大的PHP整合開發環境

Atom編輯器mac版下載
最受歡迎的的開源編輯器