一条 CSS 让你实现长列表优化 - content-visibility

一条 CSS 让你实现长列表优化 - content-visibility

相关的 CSS 属性:

content-visibility - CSS: Cascading Style Sheets | MDN (mozilla.org)

contain-intrinsic-size - CSS: Cascading Style Sheets | MDN (mozilla.org)

01 content-visibility

属性控制一个元素是否渲染其内容,它允许用户代理(浏览器)潜在地省略大量布局和渲染工作,直到需要它为止。适合做一些长列表优化和虚拟列表等

1
2
3
4
/* 属性:visible、hidden、auto */
content-visibility: visible;
content-visibility: hidden;
content-visibility: auto;
  • visible:默认属性,无任何作用。
  • hidden: 与 display: none 类似
  • auto: 判断被设置的该属性的元素是否在可视区,在可视区,则会渲染此元素;否则,不会渲染此元素

我们浅做一个对比实验,让页面需要渲染大量的 DOM 元素(10000 次),我们使用和不使用的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
content-visibility: auto;
}
</style>
</head>
<body>
<div id="boxs"></div>
<script>
function renderBox(num) {
var boxs = document.getElementById('boxs')
var html = ''
for (var i = 0; i < num; i++) {
html += `<div class="box">
<h1>content-visibility</h1>
The content-visibility CSS property controls whether or not an element renders its contents at all, along with forcing a strong set of containments, allowing user agents to potentially omit large swathes of layout and rendering work until it becomes needed. Basically it enables the user agent to skip an element's rendering work (including layout and painting) until it is needed — which makes the initial page load much faster.
</div>`
}
boxs.innerHTML = html
}

renderBox(10000)
</script>
</body>
</html>

使用 content-visibility: auto; ,发现渲染部分花费了 191ms

image-20220620115839803

没有使用,渲染部分整整花费了 1619ms

image-20220620120140346

结论: 相同的环境下测,使用了 content-visibility: auto; ,优化了 89% ,从1619ms => 191ms

问题:由于下方的元素在滚动的过程中,出现在视口范围内才被渲染,因此,滚动条出现了明显的飘忽不定的抖动现象。(当然这也是使用了 content-visibility: auto 的一个小问题之一),不过明显可以看出,这与我们通常使用 JavaScript 实现的懒加载或者延迟加载非常类似。

当然,与懒加载不同的是,在向下滚动的过程中,上方消失的已经被渲染过且消失在视口的元素,也会因为消失在视口中,重新被隐藏。因此,即便页面滚动到最下方,整体的滚动条高度还是没有什么变化的。

image-20220620135712297image-20220620135804645

02 利用 contain-intrinsic-size 解决滚动条抖动问题

1
2
3
4
.box {
content-visibility: auto;
contain-intrinsic-size: 220px; /* 填写对应的高度。如果如法准确知道高度,也可以填写一个大概的值 */
}

如此之后,浏览器会给未被实际渲染的视口之外的 .box 元素一个高度,避免出现滚动条抖动的现象:

image-20220620140407166

03 兼容性问题

这个是从 “content-visibility” | Can I use… Support tables for HTML5, CSS3, etc 获取到兼容性一览(2022.6.20)

image-20220620140747062

可以发现,目前兼容率只能达到大约70%, 并前还是有出现 Safari 主流浏览器出现不兼容情况,当然,由于该属性属于渐进增强一类的功能,即便失效,也完全不影响页面本身的展示。