只需一行CSS代碼,讓長列表網(wǎng)頁的渲染性能提升幾倍以上!
點(diǎn)擊上方關(guān)注 前端技術(shù)江湖,一起學(xué)習(xí),天天進(jìn)步
作者:梨香
https://juejin.cn/post/6908521872577527822
長列表網(wǎng)頁相信大多數(shù)開發(fā)者都遇到過,在DOM元素過多的情況下,瀏覽器渲染會(huì)很慢,非常影響用戶體驗(yàn)。
因此我們會(huì)經(jīng)常采用虛擬滾動(dòng)、分頁、上拉加載更多等不同的方式來進(jìn)行優(yōu)化,這些方式的思想都是一樣的,都是只渲染可見區(qū)域,等用戶需要時(shí)再加載更多的內(nèi)容。而以上的方式無論哪種,都需要寫大量的js或者css邏輯去實(shí)現(xiàn)。
而現(xiàn)在,我們多了一種方式——content-visibility。只需要一行CSS代碼,就可以實(shí)現(xiàn)可見網(wǎng)頁只加載可見區(qū)域內(nèi)容,使網(wǎng)頁的渲染性能得到數(shù)倍的提升!
介紹
content-visibility是一個(gè)css屬性,它控制一個(gè)元素是否呈現(xiàn)其內(nèi)容,能讓用戶潛在地控制元素的呈現(xiàn)。用戶可以使用它跳過元素的呈現(xiàn)(包括布局和繪制),直到用戶需要為止,讓頁面的初始渲染得到極大的提升。
value
content-visibility屬性有三個(gè)可選值:
visible: 默認(rèn)值。對布局和呈現(xiàn)不會(huì)產(chǎn)生什么影響。 hidden: 元素跳過其內(nèi)容的呈現(xiàn)。用戶代理功能(例如,在頁面中查找,按Tab鍵順序?qū)Ш降龋┎豢稍L問已跳過的內(nèi)容,也不能選擇或聚焦。類似于對其內(nèi)容設(shè)置了display: none屬性。 auto: 對于用戶可見區(qū)域的元素,瀏覽器會(huì)正常渲染其內(nèi)容;對于不可見區(qū)域的元素,瀏覽器會(huì)暫時(shí)跳過其內(nèi)容的呈現(xiàn),等到其處于用戶可見區(qū)域時(shí),瀏覽器在渲染其內(nèi)容。
效果對比
使用前
代碼
如下代碼,在瀏覽器中簡單的使用100個(gè)卡片,并對其設(shè)置掃光效果動(dòng)畫:
<html>
<head>
<title>content-visibility</title>
<style type="text/css">
.card {
position: relative;
overflow: hidden;
transition-duration: 0.3s;
margin-bottom: 10px;
width: 200px;
height: 100px;
background-color: #ffaa00;
}
.card:before {
content: '';
position: absolute;
left: -665px;
top: -460px;
width: 300px;
height: 15px;
background-color: rgba(255, 255, 255, 0.5);
transform: rotate(-45deg);
animation: searchLights 2s ease-in 0s infinite;
}
@keyframes searchLights {
0% {
}
75% {
left: -100px;
top: 0;
}
100% {
left: 120px;
top: 100px;
}
}
</style>
</head>
<body>
<div class="card"></div>
<div class="card"></div>
<!-- ... -->
<!-- 此處省略97個(gè)<div class="card"></div> -->
<!-- ... -->
<div class="card"></div>
</body>
</html>
渲染效果
從chrome可以看出,渲染時(shí)間花費(fèi)了1454ms:

使用后
代碼
在class為card中添加 content-visibility: auto;:
.card {
position: relative;
overflow: hidden;
transition-duration: 0.3s;
margin-bottom: 10px;
width: 200px;
height: 100px;
background-color: #ffaa00;
content-visibility: auto;
}
.card:before {
content: '';
// ...
渲染效果
可以明顯的看到,使用content-visibility: auto;后渲染時(shí)間只需要381ms,性能提升了近4倍!而且隨著元素內(nèi)容變復(fù)雜,提升的性能會(huì)有更明顯的上升。

再從下圖的dom結(jié)構(gòu)變化中也可以看到,當(dāng)card未出現(xiàn)在屏幕可見區(qū)域內(nèi)是,其內(nèi)容(::before等動(dòng)畫)在元素出現(xiàn)在可見效果時(shí)才出現(xiàn):

缺陷
兼容性
content-visibility是chrome85今年新增的特性,所以目前兼容性還不高,但是相信兼容性的問題在不久的將來會(huì)得到解決。目前兼容性如下:

部分元素導(dǎo)致瀏覽器渲染出問題
問題
當(dāng)元素的部分內(nèi)容如<img />標(biāo)簽這種,元素的高度是有圖片內(nèi)容決定的,因此在這種情況下,如果使用content-visibility,則可見視圖外的img初始未渲染,高度為0,隨著滾動(dòng)條向下滑動(dòng),頁面高度增加,會(huì)導(dǎo)致滾動(dòng)條的滾動(dòng)有問題。
<html>
<head>
<title>content-visibility</title>
<style type="text/css">
.card {
margin-bottom: 10px;
content-visibility: auto;
}
</style>
</head>
<body>
<div class="card">
<img
src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1057266467,784420394&fm=26&gp=0.jpg"
alt="小狗"
/>
<!-- ... -->
<!-- 此處省略n個(gè)card內(nèi)容 -->
<!-- ... -->
<img
src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1057266467,784420394&fm=26&gp=0.jpg"
alt="小狗"
/>
</div>
</body>
</html>
效果如下,可以看出滾動(dòng)條隨著圖片的呈現(xiàn),會(huì)出現(xiàn)問題:

解決思路
解決此問題,如果在已知元素高度的情況下,可以使用contains-intrinsic-size屬性,為上面的card添加:contains-intrinsic-size:312px;,這會(huì)給內(nèi)容附一個(gè)初始高度值。(如果高度不固定也可以附一個(gè)大致的初始高度值,會(huì)使?jié)L動(dòng)條問題相對減少)。
修改代碼如下:
<style type="text/css">
.card {
margin-bottom: 10px;
content-visibility: auto;
contain-intrinsic-size: 312px; // 添加此行
}
</style>
再次看滾動(dòng)條就沒有問題了:

總結(jié)
content-visibility是一個(gè)非常實(shí)用的CSS屬性,通過一行CSS可以代替虛擬滾動(dòng)、上拉加載更多等多種長列表渲染優(yōu)化方式。
雖然其兼容性現(xiàn)在不是很好,但是相信不久的將來這并不是問題。現(xiàn)在來看是部分場景下它對瀏覽器的滾動(dòng)條影響問題,如果你的列表項(xiàng)高度相同,那么可以通過contain-intrinsic-size來設(shè)置一個(gè)初始高度解決。如果列表項(xiàng)高度不固定而又非常重視用戶的滾動(dòng)條體驗(yàn),那么不建議使用此屬性。當(dāng)然了,這一css屬性出來的時(shí)間并不是太長,雖然它的完善,這一問題或許在將來也能夠得到解決。
The End
歡迎自薦投稿到《前端技術(shù)江湖》,如果你覺得這篇內(nèi)容對你挺有啟發(fā),記得點(diǎn)個(gè) 「在看」哦
點(diǎn)個(gè)『在看』支持下 
