1. 程式人生 > 其它 >css - content-visibility

css - content-visibility

css - content-visibility

content-visibility:實現可見網頁只加載可見區域內容

介紹

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

value

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

visible: 預設值。對佈局和呈現不會產生什麼影響。
hidden: 元素跳過其內容的呈現。使用者代理功能(例如,在頁面中查詢,按Tab鍵順序導航等)不可訪問已跳過的內容,也不能選擇或聚焦。類似於對其內容設定了display: none屬性。
auto: 對於使用者可見區域的元素,瀏覽器會正常渲染其內容;對於不可見區域的元素,瀏覽器會暫時跳過其內容的呈現,等到其處於使用者可見區域時,瀏覽器在渲染其內容。

demo

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

使用前

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

<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個<div class="card"></div> -->
    <!-- ... -->
    <div class="card"></div>
  </body>
  <script>
    document.body.innerHTML=Array(100).fill('<div class="card"></div>').join('\n')
  </script>
</html>

使用後

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

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

缺陷

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

部分元素導致瀏覽器渲染出問題
問題
當元素的部分內容如標籤這種,元素的高度是有圖片內容決定的,因此在這種情況下,如果使用content-visibility,則可見檢視外的img初始未渲染,高度為0,隨著滾動條向下滑動,頁面高度增加,會導致滾動條的滾動有問題。
如下程式碼:

<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個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;,這會給內容附一個初始高度值。(如果高度不固定也可以附一個大致的初始高度值,會使滾動條問題相對減少)。
修改程式碼如下:

<style type="text/css">
  .card {
    margin-bottom: 10px;
    content-visibility: auto;
    contain-intrinsic-size: 312px; // 新增此行
  }
</style>

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

總結

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

參考資料

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