只需一行 CSS 代碼,讓長列表網頁的渲染性能提升幾倍以上!

長列表網頁相信大多數開發者都遇到過,在 DOM 元素過多的情況下,瀏覽器渲染會很慢,非常影響用戶體驗。

因此我們會經常採用虛擬滾動、分頁、上拉加載更多等不同的方式來進行優化,這些方式的思想都是一樣的,都是隻渲染可見區域,等用戶需要時再加載更多的內容。而以上的方式無論哪種,都需要寫大量的 js 或者 css 邏輯去實現。而現在,我們多了一種方式——content-visibility。只需要一行 CSS 代碼,就可以實現可見網頁只加載可見區域內容,使網頁的渲染性能得到數倍的提升!

介紹

content-visibility 是一個 css 屬性,它控制一個元素是否呈現其內容,能讓用戶潛在地控制元素的呈現。用戶可以使用它跳過元素的呈現 (包括佈局和繪製),直到用戶需要爲止,讓頁面的初始渲染得到極大的提升。

value

content-visibility 屬性有三個可選值:

效果對比

使用前

代碼

如下代碼,在瀏覽器中簡單的使用 100 個卡片,並對其設置掃光效果動畫:

  <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個<div class="card"></div> -->  
    <!-- ... -->  
    <div class="card"></div>  
  </body>  
</html>

渲染效果

從 chrome 可以看出,渲染時間花費了 1454ms:

使用後

代碼

在 class 爲 card 中添加 content-visibility: auto;

    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;後渲染時間只需要 381ms,性能提升了近 4 倍!而且隨着元素內容變複雜,提升的性能會有更明顯的上升。

再從下圖的 dom 結構變化中也可以看到,當 card 未出現在屏幕可見區域內是,其內容 (::before 等動畫) 在元素出現在可見效果時纔出現:

缺陷

兼容性

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

部分元素導致瀏覽器渲染出問題

問題

當元素的部分內容如<img />標籤這種,元素的高度是有圖片內容決定的,因此在這種情況下,如果使用content-visibility,則可見視圖外的 img 初始未渲染,高度爲 0,隨着滾動條向下滑動,頁面高度增加,會導致滾動條的滾動有問題。

  <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個card內容 -->  
      <!-- ... -->  
      <img  
        src="https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1057266467,784420394&fm=26&gp=0.jpg"  
        alt="小狗"  
      />  
    </div>  
  </body>  
</html>

效果如下,可以看出滾動條隨着圖片的呈現,會出現問題:

解決思路

解決此問題,如果在已知元素高度的情況下,可以使用contains-intrinsic-size屬性,爲上面的 card 添加:contains-intrinsic-size:312px;,這會給內容附一個初始高度值。(如果高度不固定也可以附一個大致的初始高度值,會使滾動條問題相對減少)。修改代碼如下:

      .card {  
        margin-bottom: 10px;  
        content-visibility: auto;  
        contain-intrinsic-size: 312px; // 添加此行  
      }  
    </style>

再次看滾動條就沒有問題了:

總結

content-visibility 是一個非常實用的 CSS 屬性,通過一行 CSS 可以代替虛擬滾動、上拉加載更多等多種長列表渲染優化方式。雖然其兼容性現在不是很好,但是相信不久的將來這並不是問題。現在來看是部分場景下它對瀏覽器的滾動條影響問題,如果你的列表項高度相同,那麼可以通過contain-intrinsic-size來設置一個初始高度解決。如果列表項高度不固定而又非常重視用戶的滾動條體驗,那麼不建議使用此屬性。當然了,這一 css 屬性出來的時間並不是太長,雖然它的完善,這一問題或許在將來也能夠得到解決。

作者:Dwan

https://juejin.cn/post/6908521872577527822

推薦關注「前端大全」,提升前端技能

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/TUNoJCSSW_XWRJHbglqZDA