当前位置: 首页 > 科技观察

使用新的CSS功能直接实现虚拟列表?稍后JS

时间:2023-03-13 08:48:47 科技观察

什么是content-visibility?content-visibility:该属性控制元素是否呈现其内容,这允许用户代理(浏览器)在需要时可能省略大量布局和呈现工作。MDN原文:content-visibilityCSS属性控制元素是否完全呈现其内容,并强制包含一组强大的内容,从而允许用户代理潜在地省略大量的布局和呈现工作,直到它变得非常需要为止。Basic使用户代理能够跳过元素的渲染工作(包括布局和绘画)直到需要它——这使得初始页面加载速度更快。它有几个共同的价值观。/*关键字取值*/content-visibility:visible;content-visibility:hidden;content-visibility:auto;另行说明:content-visibility:visible:默认值,无作用,相当于没有添加内容可见性,元素照常呈现。content-visibility:hidden:类似于display:none,用户代理将跳过其内容的呈现。(这里要注意内容的渲染是跳过的)content-visibility:auto:如果元素不在屏幕上,与用户无关,则不会渲染其后代元素。contain-intrinsic-size当然,除了content-visibility,还有一个匹配的属性——contain-intrinsic-size。contain-intrinsic-size:控制由content-visibility指定的元素的固有大小。上面两个属性光看定义和介绍会有点混乱。让我们首先看看内容可见性是如何使用的。content-visibility:visible为默认值,添加后没有任何作用,我们直接跳过。使用content-visibility:hidden来优化显示切换性能。首先,让我们看一下content-visibility:hidden。通常与display:none比较,但两者还是有区别的。有一个很大的不同。首先,假设我们有两个DIV环绕框:

1111
2222
设置两个div一个黑色200x200块:.g-wrap>div{width:200px;高度:200px;background:#000;}效果如下:OK,没问题,接下来,我们给.hidden设置content-visibility:hidden,看看会发生什么:.hidden{content-visibility:hidden;}效果是如下:注意,仔细看效果,这里添加了content-visibility:hidden之后,消失的只是被添加元素的div的子元素消失了,而父元素本身和它的样式仍然存在于页面上。如果我们去掉设置了content-visibility:hidden的元素本身的width,height,padding,margin等属性,元素看起来像Setdisplay:none一般会消失在页面上。那么,content-visibility:hidden的作用是什么?对于设置了content-visibility:hidden的元素,其子元素将被隐藏,但其渲染状态将被缓存。因此,当content-visibility:hidden被移除时,用户代理不需要从头开始重新渲染它和它的孩子。因此,如果我们将这个属性应用到一些一开始需要隐藏,然后需要在页面某个时刻渲染的元素,或者一些需要频繁切换显示和隐藏状态的元素,渲染效率会提高。一个非常大的改进。使用content-visibility:auto实现懒加载或者虚拟列表OK,然后是content-visibility的核心用法,使用auto属性值。content-visibility:auto的作用是,如果元素在屏幕外并且与用户不相关,则不会渲染其后代元素。是不是很像LazyLoad?我们来看这样一个DEMO来理解它的功能:假设我们有这样一个HTML结构,里面有很多文本内容:...
//...包含N个段落...
每个.paragraph的内容如下:因此,整个页面看起来像这样:由于我们没有对任何页面内容进行处理,所以所有的.paragraph都会在页面刷新的瞬间渲染出来,看到的效果如上图。当然,现代浏览器正变得越来越智能。基于这种场景,我们真的希望我们可以延迟加载尚未看到或滚动到的区域。只有当我们需要显示和滚动到那个地方时,才会渲染之前的页面内容。基于这种场景,content-visibility:auto应运而生,让浏览器判断设置了这个属性的元素,如果当前不在视口中,则不渲染该元素。在上面代码的基础上,我们只需要最小化,加上这么一段代码:.paragraph{content-visibility:auto;}然后看效果,仔细观察右边的滚动条:这里我用了::-webkit-scrollbar相关样式,使滚动条更加明显。也许你还没有意识到发生了什么。下面对比一下添加content-visibility:auto和不添加content-visibility:auto两种效果下的文字整体高度有很明显的区别,这是因为有content-visibility:auto的元素没有渲染在不可见区域,所以右边内容的高度其实比正常状态切的少了很多。好吧,让我们真正开始滚动,看看会发生什么:由于下面的元素只有在滚动过程中出现在视口内时才会被渲染,所以滚动条有明显的无规律抖动。(当然,这也是使用content-visibility:auto的小问题之一),但是可以很明显的看出,这和我们平时使用JavaScript实现的延迟加载或延迟加载非常相似。当然,和懒加载不同的是,在向下滚动的过程中,上面消失的已经渲染消失在视口中的元素,也会因为消失在视口中而再次隐藏。因此,即使页面滚动到底部,滚动条的整体高度也保持不变。内容可见性可以优化渲染性能吗?那么,content-visibility可以优化渲染性能吗?在Youtube--Slashinglayoutcostwithcontent-visibility[1]中,给出了一个很好的例子。这里我简单复现一下。对于一个包含大量HTML内容的页面,比如这个页面--HTML-LivingStandard[2],你可以感觉到向下滚动,没有尽头。(这里我是在本地模拟页面,把页面的DOM全部复制过来,并没有在网站上实际测试)如果不对这个页面做任何处理,看看第一次渲染的耗时:可以看到DOMContentLoaded的时间3s+,整整2900ms都花在了Rendering上!而如果在这个页面的每一段都加上content-visibility:auto,再看整体耗时:可以看到DOMContentLoaded的耗时降到了500ms+,而OnRendering耗时,直接优化到61ms!2900ms-->61ms,可谓是惊人的优化程度。因此content-visibility:auto对长文本和长列表功能的优化是显而易见的。使用contain-intrinsic-size解决滚动条抖动问题当然content-visibility也有一些小问题。从上面的例子我们也可以看出,当使用content-visibility:auto来处理长文本和长列表时。滚动页面的时候,滚动条一直抖动,体验不是很好。当然,这也是很多虚拟榜单都会存在的一些问题。幸运的是,规范制定者也发现了这个问题。这里我们可以使用另一个CSS属性,也就是文章开头提到的另一个属性——contain-intrinsic-size来解决这个问题。contain-intrinsic-size:控制由content-visibility指定的元素的固有大小。这意味着什么?还是上面的例子...//...包含N个段落...如果我们不使用contain-intrinsic-size,只对视口外的元素使用content-visibility:auto,那么视口外的元素高度通常为0。当然,如果你直接设置父元素的固定高度,它也将有一个高度。然后是实际的滚动效果,滚动条是抖动的:所以,我们可以同时使用contain-intrinsic-size,如果我们能准确的知道渲染状态设置了content-visibility:auto的元素高度,填充在相应的高度。如果你准确知道高度,你也可以填写一个近似值:.paragraph{content-visibility:auto;contain-intrinsic-size:320px;}之后浏览器会给未真正渲染的视口.paragraph元素有个高度,避免滚动条抖动的现象:大家可以自己试试:CodePenDemo--content-visibility:autoDemo[3]content-visibility的其他一些问题首先看content-visibility的兼容性(2022-06-03):还是比较惨淡,我也没有实际使用过它正在营业,所以我需要等待一段时间。当然,由于这个属性属于渐进增强的功能,所以即使失败了,也完全不会影响页面本身的显示。同时也有同学表示使用content-visibility:auto只能解决部分场景,在海量DOM场景下的实际效果还有待进一步测试。实际使用时,多做比较再做选择。当然,现代浏览器已经越来越智能,类似于content-visibility的属性也越来越多。在性能优化的道路上,我们有更多的选择总是一件好事。参考[1]Youtube——通过内容可见性削减布局成本:https://www.youtube.com/watch?v=FFA-v-CIxJQ&t=869s[2]L——生活标准:https://html。spec.whatwg.org/[3]CodePen演示——内容可见性:自动演示:https://codepen.io/Chokcoco/pen/rNJvPEX