프런트 엔드 직원에게 가장 골치 아픈 것은 페이지 성능입니다. 사용자는 페이지를 방문할 때 항상 페이지가 대화형 상태로 빠르게 표시되기를 원합니다. 페이지가 너무 느리게 로드되면 사용자가 떠날 가능성이 높습니다. 따라서 프런트엔드 개발자에게는 페이지 성능이 최우선 사항입니다. 실제로 로딩부터 렌더링까지 전체 프로세스를 이해하면 어디서부터 시작해야 할지 알 수 있습니다.
글쎄, 벗어나지 마세요. 오늘은 주로 긴 목록 페이지의 렌더링 성능을 연구하겠습니다.
요즘에는 페이지가 점점 더 복잡해지고 있으며, 페이지에는 가장 일반적인 요소가 많이 포함되는 경우가 많습니다. 수만 개의 제품 목록이 지연 없이 렌더링되도록 하려면 어떻게 해야 합니까? 이러한 긴 목록 렌더링 시나리오에 직면했을 때 사람들은 일반적으로 일회성 렌더링에 대한 부담을 줄이기 위해 페이징 또는 가상 목록을 사용합니다. 페이지에 있지만 이러한 방법을 조정해야 하는데 JS가 함께 제공되므로 CSS만 사용하여 구현할 수 있는 솔루션이 있습니까?
대답은 '예'입니다. 콘텐츠 가시성(content-visibility)이 바로 오늘날 우리의 주인공입니다. [추천 학습: css 비디오 튜토리얼]
content-visibility
은 CSS의 새로운 속성으로 주로 페이지 렌더링 성능을 향상시키는 데 사용됩니다. 는 요소가 콘텐츠를 렌더링할지 여부를 제어하고 브라우저가 이러한 요소의 레이아웃 및 렌더링을 건너뛸 수 있도록 허용합니다.content-visibility
是CSS新增的属性,主要用来提高页面渲染性能,它可以控制一个元素是否渲染其内容,并且允许浏览器跳过这些元素的布局与渲染。
display: none
。上面说到content-visibility: hidden
的效果与display: none
类似,但其实两者还是有比较大的区别的:
从这上面我们可以看到,添加了content-visibility: hidden
元素的子元素确实是没有渲染,但它自身是会渲染的!
我们仔细想想,页面上虽然会有很多元素,但是它们会同时呈现在用户眼前吗,很显然是不会的,用户每次能够真实看到就只有设备可见区那些内容,对于非可见区的内容只要页面不发生滚动,用户就永远看不到。虽然用户看不到,但浏览器却会实实在在的去渲染,以至于浪费大量的性能。所以我们得想办法让浏览器不渲染非可视区的内容就能够达到提高页面渲染性能的效果。
我们上面说到的虚拟列表原理其实就跟这个类似,在首屏加载时,只加载可视区
的内容,当页面发生滚动时,动态通过计算获得可视区
的内容,并将非可视区
的内容进行删除,这样就能够大大提高长列表的渲染性能。
但这个需要配合JS才能实现,现在我们可以使用CSS中content-visibility: auto
,它可以用来跳过屏幕外的内容渲染,对于这种有大量离屏内容的长列表,可以大大减少页面渲染时间。
我们将上面的例子稍微改改:
<template> <div> <div> <img :src="book.bookCover" / alt="페이지 렌더링 성능을 향상시키는 데 도움이 되는 새로운 CSS 기능인 콘텐츠 가시성에 대해 이야기해 보겠습니다." > <div> <div>{{ `${book.bookName}${index + 1}` }}</div> <div>{{ book.catlog }}</div> <div> <div v-for="(item, index) in book.tags" :key="index"> {{ item }} </div> </div> <div> {{ book.desc }} </div> </div> </div> </div> </template> <script setup> import { toRefs } from "vue"; const props = defineProps<{ book: any; index: any; }>(); const { book, index } = toRefs(props); </script> <style scoped> .card_item { margin: 20px auto; content-visibility: auto; } / * ... */ </style>
首先是没有添加content-visibility: auto
display: none
을 설정하는 것과 유사합니다. content-visibility:hidden
효과와 유사 display: none
, 그러나 실제로 둘 사이에는 큰 차이가 있습니다.
content-visibility:hidden
요소가 추가된 하위 요소는 실제로 렌더링되지 않지만 자체적으로 렌더링되는 것을 볼 수 있습니다! 🎜비주얼 영역
의 내용만 로드됩니다. 계산을 통해 동적으로 얻어지는 영역의 내용과 비표시 영역
의 내용이 삭제되므로 긴 목록의 렌더링 성능이 크게 향상될 수 있습니다. 🎜🎜하지만 이는 JS로 구현되어야 합니다. 이제 CSS에서 content-visibility: auto
를 사용하여 이러한 종류의 콘텐츠에 대해 화면 밖의 콘텐츠 렌더링을 건너뛸 수 있습니다. 화면 밖에 콘텐츠가 많을 경우 목록이 길면 페이지 렌더링 시간이 크게 단축될 수 있습니다. 🎜🎜위의 예를 약간 변경했습니다. 🎜.card_item { content-visibility: auto; }🎜우선
content-visibility: auto
효과가 추가되지 않았습니다. 이러한 요소는 가시 영역에 있는지 여부에 관계없이 렌더링됩니다. 🎜🎜🎜🎜 일반적인 비즈니스에서 이렇게 쓰면 사용자가 이 페이지에 들어간 후 바로 향수를 뱉을 수 있습니다. 성능을 고려하여 다음을 추가합니다. 🎜/* Keyword values */ contain-intrinsic-width: none; /* <length> values */ contain-intrinsic-size: 1000px; contain-intrinsic-size: 10rem; /* width | height */ contain-intrinsic-size: 1000px 1.5em; /* auto <length> */ contain-intrinsic-size: auto 300px; /* auto width | auto height */ contain-intrinsic-size: auto 300px auto 4rem;🎜이때 효과를 살펴보겠습니다. 🎜
从第10个开始,这些没在可视区的元素就没有被渲染,这可比上面那种全部元素都渲染好太多了,但是如果浏览器不渲染页面内的一些元素,滚动将是一场噩梦,因为无法正确计算页面高度。这是因为,content-visibility
会将分配给它的元素的高度(height
)视为0
,浏览器在渲染之前会将这个元素的高度变为0
,从而使我们的页面高度和滚动变得混乱。
这里我们可以看到页面上的滚动条会出现抖动现象,这是因为可视区外的元素只有出现在了可视区才会被渲染,这就回导致前后页面高度会发生变化,从而出现滚动条的诡异抖动现象,这是虚拟列表基本都会存在的问题。
⚠️注意:当元素接近视口时,浏览器不再添加size
容器并开始绘制和命中测试元素的内容。这使得渲染工作能够及时完成以供用户查看。
这也是为什么上面我们看到的是从第十个才开始不渲染子元素,因为它需要一个缓冲区以便浏览器能够在页面发生滚动时及时渲染呈现在用户眼前。
上面提到的size
其实是一种 CSS 属性的潜在值contain
,它指的是元素上的大小限制确保元素的框可以在不需要检查其后代的情况下进行布局。这意味着如果我们只需要元素的大小,我们可以跳过后代的布局。
页面在滚动过程中滚动条一直抖动,这是一个不能接受的体验问题,为了更好地实现content-visibility
,浏览器需要应用 size containment 以确保内容的渲染结果不会以任何方式影响元素的大小。这意味着该元素将像空的一样布局。如果元素没有在常规块布局中指定的高度,那么它将是 0 高度。
这个时候我们可以使用contain-intrinsic-size
来指定的元素自然大小,确保我们未渲染子元素的 div 仍然占据空间,同时也保留延迟渲染的好处。
此属性是以下 CSS 属性的简写:
contain-intrinsic-width
contain-intrinsic-height
/* Keyword values */ contain-intrinsic-width: none; /* <length> values */ contain-intrinsic-size: 1000px; contain-intrinsic-size: 10rem; /* width | height */ contain-intrinsic-size: 1000px 1.5em; /* auto <length> */ contain-intrinsic-size: auto 300px; /* auto width | auto height */ contain-intrinsic-size: auto 300px auto 4rem;
contain-intrinsic-size 可以为元素指定以下一个或两个值。如果指定了两个值,则第一个值适用于宽度,第二个值适用于高度。如果指定单个值,则它适用于宽度和高度。
我们只需要给添加了content-visibility: auto
的元素添加上contain-intrinsic-size
就能够解决滚动条抖动的问题,当然,这个高度约接近真实渲染的高度,效果会越好,如果实在无法知道准确的高度,我们也可以给一个大概的值,也会使滚动条的问题相对减少。
.card_item { content-visibility: auto; contain-intrinsic-size: 200px; }
之前没添加contain-intrinsic-size
属性时,可视区外的元素高度都是0,现在这些元素高度都是我们设置的contain-intrinsic-size
的值,这样的话整个页面的高度就是不会发生变化(或者说变化很小),从而页面滚动条也不会出现抖动问题(或者说抖动减少)
上面说了这么多,content-visibility
是否真的能够提高页面的渲染性能呢,我们来实际对比看看:
content-visibility
的页面渲染content-visibility
的页面渲染上面是用1000个列表元素进行测试的,有content-visibility
的页面渲染花费时间大概是37ms,而没有content-visibility
的页面渲染花费时间大概是269ms,提升了足足有7倍之多!!!
对于列表元素更多的页面,content-visibility
带来的渲染性能提升会更加明显。
之前有同学问到了content-visibility: auto
是否会减少页面内存的占用,这个我们可以查看下使用前后页面所占用内存的大小是否有变化。
我们可以通过chrome浏览器 设置 --> 更多工具 --> 任务管理器
查看页面占用内存大小。
content-visibility: auto
,页面占用内存大概为96.2MBcontent-visibility: auto
,页面占用内存仍然是96.2MB也就是说,它并不会减少页面占用内存大小,这些元素是真实存在于DOM树中的,并且我们也可以通过JS访问到
如果我们在添加了content-visibility: auto
的元素内去加载脚本,并且此时的元素处于一个不可见的状态,那么此时元素内的脚本能够正常加载呢?
<!-- ... 第十二个 --> <div class="visibility_item"> <div class="inner"> 测试脚本 <img src="../../../../images/22-11/페이지 렌더링 성능을 향상시키는 데 도움이 되는 새로운 CSS 기능인 콘텐츠 가시성에 대해 이야기해 보겠습니다." alt=""> <script src="./2.js"></script> </div> </div>
很明显它并不会影响脚本与图片的加载行为,并且脚本再加载后能够正常执行。结合上面第一点,我们可以得出结论,使用了content-visibility: auto
的元素影响的只是子元素的渲染,对于内部静态资源的加载还是正常进行。
但我们需要注意的是脚本的执行时机,如果要获取DOM元素的话,此时的脚本只能获取到它加载位置之前的DOM元素,而与它自身DOM有没有渲染无关!
// 2.js console.log('测试脚本') console.log('第十一个', document.querySelectorAll('.visibility_item')[10]) console.log('第十三个', document.querySelectorAll('.visibility_item')[12])
使用了content-visibility: auto
并且在非可视区的元素是否存在于可访问树中?
这里我们可以看出content-visibility: auto
是屏幕外的内容在文档对象模型中仍然可用,因此在可访问性树中(与visibility: hidden
不同)。这意味着我们可以在页面上搜索并导航到该内容,而无需等待它加载或牺牲渲染性能。
这个功能特性是在chrome 90 中更新的,在 chrome 85-89 中,屏幕外的子元素content-visibility: auto
被标记为不可见。
content-visibility是chrome85新增的特性,所以兼容性还不是很高,但它是一个非常实用的CSS属性,由于跳过了渲染,如果我们大部分内容都在屏幕外,利用该content-visibility
属性可以使初始用户加载速度更快。相信兼容性的问题在不久的将来会得到解决~
原文地址:https://juejin.cn/post/7168629736838463525
(学习视频分享:web前端)
위 내용은 페이지 렌더링 성능을 향상시키는 데 도움이 되는 새로운 CSS 기능인 콘텐츠 가시성에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!