用 CSS 新特性直接实现虚拟列表?JS 往后稍稍

网站建设3年前发布
23 00

用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,​content-visibility​:属性控制一个元素是否渲染其内容,它允许用户代理(浏览器)潜在地省略大量布局和渲染工作,直到需要它为止。,它有几个常见的取值。,分别解释一下:,当然,除 ​​content-visibility​​ 之外,还有一个与之配套的属性 — ​contain-intrinsic-size​。,​​contain-intrinsic-size​​:控制由 ​​content-visibility​​ 指定的元素的自然大小。,上面两个属性光看定义和介绍会有点绕。,我们首先来看看 ​​content-visibility​​ 如何具体使用。,​​content-visibility: visible​​ 是默认值,添加后没有任何效果,我们就直接跳过。,首先来看看 ​​content-visibility: hidden​​,它通常会拿来和 ​​display: none​​ 做比较,但是其实它们之间还是有很大的不同的。,首先,假设我们有两个 DIV 包裹框:,设置两个 div 为 ​​200x200​​ 的黑色块:,效果如下:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,OK,没有问题,接下来,我们给其中的 ​​.hidden​​ 设置 ​​content-visibility: hidden​​,看看会发生什么:,效果如下:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,注意,仔细看效果,这里添加了 ​​content-visibility: hidden​​ 之后,消失的只是添加了该元素的 div 的子元素消失不见,而父元素本身及其样式,还是存在页面上的。,如果我们去掉设置了 ​​content-visibility: hidden​​ 的元素本身的 ​​width​​、​​height​​、​​padding​​、​​margin​​ 等属性,则元素看上去就如同设置了 ​​display: none​​ 一般,在页面上消失不见了。,那么,​​content-visibility: hidden​​ 的作用是什么呢?,设置了 ​​content-visibility: hidden​​ 的元素,其元素的子元素将被隐藏,但是,它的渲染状态将会被缓存。所以,当 ​​content-visibility: hidden​​ 被移除时,用户代理无需重头开始渲染它和它的子元素。,因此,如果我们将这个属性应用在一些一开始需要被隐藏,但是其后在页面的某一时刻需要被渲染,或者是一些需要被频繁切换显示、隐藏状态的元素上,其渲染效率将会有一个非常大的提升。,OK,接下来是 ​​content-visibility​​ 的核心用法,利用 ​​auto​​ 属性值。,​​content-visibility: auto​​ 的作用是,如果该元素不在屏幕上,并且与用户无关,则不会渲染其后代元素。是不是与 LazyLoad 非常类似?,我们来看这样一个 DEMO ,了解其作用:,假设,我们存在这样一个 HTML 结构,含有大量的文本内容:,每个 ​​.paragraph​​ 的内容如下:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,因此,整个的页面看起来就是这样的:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,由于,我们没有对页面内容进行任何处理,因此,所有的 ​​.paragraph​​ 在页面刷新的一瞬间,都会进行渲染,看到的效果就如上所示。,当然,现代浏览器愈加趋于智能,基于这种场景,其实我们非常希望对于仍未看到,仍旧未滚动到的区域,可以延迟加载,只有到我们需要展示、滚动到该处时,页面内容才进行渲染。,基于这种场景,​​content-visibility: auto​​ 就应运而生了,它允许浏览器对于设置了该属性的元素进行判断,如果该元素当前不处于视口内,则不渲染该元素。,我们基于上述的代码,只需要最小化,添加这样一段代码:,再看看效果,仔细观察右侧的滚动条:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,可能你还没意识到发生了什么,我们对比下添加了 ​​content-visibility: auto​​ 和没有添加 ​​content-visibility: auto​​ 的两种效果下文本的整体高度:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,有着非常明显的差异,这是因为,设置了 ​​content-visibility: auto​​ 的元素,在非可视区域内,目前并没有被渲染,因此,右侧内容的高度其实是比正常状态下少了一大截的。,好,我们实际开始进行滚动,看看会发生什么:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,由于下方的元素在滚动的过程中,出现在视口范围内才被渲染,因此,滚动条出现了明显的飘忽不定的抖动现象。(当然这也是使用了 ​​content-visibility: auto​​ 的一个小问题之一),不过明显可以看出,这与我们通常使用 JavaScript 实现的懒加载或者延迟加载非常类似。,当然,与懒加载不同的是,在向下滚动的过程中,上方消失的已经被渲染过且消失在视口的元素,也会因为消失在视口中,重新被隐藏。因此,即便页面滚动到最下方,整体的滚动条高度还是没有什么变化的。,那么,​​content-visibility​​ 是否能够优化渲染性能呢?,在 Youtube — Slashing layout cost with content-visibility[1] 中,给了一个非常好的例子。,这里我简单复现一下。,对于一个存在巨量 HTML 内容的页面,譬如类似于这个页面 — HTML – Living Standard[2],用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,可以感受到,往下翻,根本翻不到尽头。(这里我在本地模拟了该页面,复制了该页面的所有 DOM,并非实际在该网站进行测试),如果不对这个页面做任何处理,看看首次渲染需要花费的时间:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,可以看到,DOMContentLoaded 的时间的 ​​3s+​​,而花费在 Rendering 上的就有整整 ​​2900ms​​!,而如果给这个页面的每个段落,添加上 ​​content-visibility: auto​​,再看看整体的耗时:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,可以看到,DOMContentLoaded 的时间骤降至了 ​​500ms+​​,而花费在 Rendering 上的,直接优化到了 ​​61ms​​!,2900ms –> 61ms,可谓是惊人级别的优化了。因此,​​content-visibility: auto​​ 对于长文本、长列表功能的优化是显而易见的。,当然,​​content-visibility​​ 也存在一些小问题。,从上面的例子,也能看到,在利用 ​​content-visibility: auto​​ 处理长文本、长列表的时候。在滚动页面的过程中,滚动条一直在抖动,这不是一个很好的体验。,当然,这也是许多虚拟列表都会存在的一些问题。,好在,规范制定者也发现了这个问题。这里我们可以使用另外一个 CSS 属性,也就是文章一开头提到的另外一个属性 — ​​contain-intrinsic-size​​,来解决这个问题。,​​contain-intrinsic-size​​:控制由 ​​content-visibility​​ 指定的元素的自然大小。,什么意思呢?,还是上面的例子,如果我们不使用 ​​contain-intrinsic-size​​,只对视口之外的元素使用 ​​content-visibility: auto​​,那么视口外的元素高度通常就为 0。,那么实际的滚动效果,滚动条就是抖动的:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,所以,我们可以同时利用上 ​​contain-intrinsic-size​​,如果能准确知道设置了 ​​content-visibility: auto​​ 的元素在渲染状态下的高度,就填写对应的高度。如果如法准确知道高度,也可以填写一个大概的值:,如此之后,浏览器会给未被实际渲染的视口之外的 ​​.paragraph​​ 元素一个高度,避免出现滚动条抖动的现象:,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,你可以自己亲自尝试感受一下:CodePen Demo — content-visibility: auto Demo[3],首先,看看 ​​content-visibility​​ 的兼容性(2022-06-03):,用 CSS 新特性直接实现虚拟列表?JS 往后稍稍,目前还是比较惨淡的,并且我没有实际在业务中使用它,需要再等待一段时间。当然,由于该属性属于渐进增强一类的功能,即便失效,也完全不影响页面本身的展示。,同时,也有一些同学表示,利用 ​​content-visibility: auto​​ 只能解决部分场景,在海量 DOM 的场景下的实际效果,还有待进一步的实测。真正运用的时候,多做对比,再做取舍。,当然,现代浏览器已经越来越智能,类似 ​​content-visibility​​ 功能的属性也越来越多,我们在性能优化的路上有了更多选择,总归是一件好事。,[1]Youtube — Slashing layout cost with content-visibility: https://www.youtube.com/watch?v=FFA-v-CIxJQ&t=869s,[2]L – Living Standard: https://html.spec.whatwg.org/,[3]CodePen Demo — content-visibility: auto Demo: https://codepen.io/Chokcoco/pen/rNJvPEX

© 版权声明

相关文章