两行CSS让页面提升了近7倍渲染性能!
前言
对于前端人员来讲,最令人头疼的应该就是页面性能了,当用户在访问一个页面时,总是希望它能够快速呈现在眼前并且是可交互状态。如果页面加载过慢,你的用户很可能会因此离你而去。所以页面性能对于前端开发者来说可谓是重中之重,其实你如果了解页面从加载到渲染完成的整个过程,就知道应该从哪方面下手了。
嗯,不要跑偏了,今天我们主要来研究长列表页面的渲染性能
现如今的页面越来越复杂,一个页面往往承载着大量的元素,最常见的就是一些电商页面,数以万计的商品列表是怎么保证渲染不卡顿的,大家在面对这种长列表渲染的场景下,一般都会采用分页或者虚拟列表来减缓页面一次性渲染的压力,但这些方式都需要配合JS来时实现,那么有没有仅使用CSS就能够实现的方案呢?
答案是有的,它就是我们今天的主角 —— 内容可见性(content-visibility)
如果这篇文章有帮助到你,️关注+点赞️鼓励一下作者,文章公众号首发,关注 前端南玖
第一时间获取最新文章~
content-visibility
属性值
content-visibility
是CSS新增的属性,主要用来提高页面渲染性能,它可以控制一个元素是否渲染其内容,并且允许浏览器跳过这些元素的布局与渲染。
- visible:默认值,没有任何效果,相当于没有添加
content-visibility
,渲染效果与往常一致 - hidden:与
display: none
类似,浏览器将跳过内容渲染(跳过的是子元素的渲染,不包含自身) - auto:如果该元素不在屏幕上,并且与用户无关,则不会渲染其子元素
content-visibility: hidden
上面说到content-visibility: hidden
的效果与display: none
类似,但其实两者还是有比较大的区别的:
- content-visibility: hidden 只是隐藏了子元素,自身不会被隐藏
- content-visibility: hidden 隐藏内容的渲染状态会被缓存,所以当它被移除或者设为可见时,浏览器不会重新渲染,而是会应用缓存,所以对于需要频繁切换显示隐藏的元素,这个属性能够极大地提高渲染性能。
从着上面我们可以看到,添加了content-visibility: hidden
元素的子元素确实是没有渲染,但它自身是会渲染的!
content-visibility: auto 虚拟列表
我们仔细想想,页面上虽然会有很多元素,但是它们会同时呈现在用户眼前吗,很显然是不会的,用户每次能够真实看到就只有设备可见区那些内容,对于非可见区的内容只要页面不发生滚动,用户就永远看不到。虽然用户看不到,但浏览器却会实实在在的去渲染,以至于浪费大量的性能。所以我们得想办法让浏览器不渲染非可视区的内容就能够达到提高页面渲染性能的效果。
我们上面说到的虚拟列表原理其实就跟这个类似,在首屏加载时,只加载可视区
的内容,当页面发生滚动时,动态通过计算获得可视区
的内容,并将非可视区
的内容进行删除,这样就能够大大提高长列表的渲染性能。
但这个需要配合JS才能实现,现在我们可以使用CSS中content-visibility: auto
,它可以用来跳过屏幕外的内容渲染,对于这种有大量离屏内容的长列表,可以大大减少页面渲染时间。
我们将上面的例子稍微改改:
<template>
<div class="card_item">
<div class="card_inner">
<img :src="book.bookCover" class="book_cover" />
<div class="card_item_right">
<div class="book_title">{{ `${book.bookName}${index + 1}` }}</div>
<div class="book_author">{{ book.catlog }}</div>
<div class="book_tags">
<div class="book_tag" v-for="(item, index) in book.tags" :key="index">
{{ item }}
</div>
</div>
<div class="book_desc">
{{ book.desc }}
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { toRefs } from "vue";
const props = defineProps<{
book: any;
index: any;
}>();
const { book, index } = toRefs(props);
</script>
<style lang="less" scoped>
.card_item {
margin: 20px auto;
content-visibility: auto;
}
/ *
...
*/
</style>
首先是没有添加content-visibility: auto
的效果,无论这些元素是否在可视区,都会被渲染
如果我们在平常业务中这样写,用户进入到这个页面可能就直接口吐芬芳了,为了性能考虑,我们为每一个列表项加上:
.card_item {
content-visibility: auto;
}
这个时候我们再来看下效果:
从第10个开始,这些没在可视区的元素就没有被渲染,这可比上面那种全部元素都渲染好太多了,但是如果浏览器不渲染页面内的一些元素,滚动将是一场噩梦,因为无法正确计算页面高度。这是因为,content-visibility
会将分配给它的元素的高度(height
)视为0
,浏览器在渲染之前会将这个元素的高度变为0
,从而使我们的页面高度和滚动变得混乱。
这里我们可以看到页面上的滚动条会出现抖动现象,这是因为可视区外的元素只有出现在了可视区才会被渲染,这就回导致前后页面高度会发生变化,从而出现滚动条的诡异抖动现象,这是虚拟列表基本都会存在的问题。
contain-intrinsic-size 救场
页面在滚动过程中滚动条一直抖动,这是一个不能接受的体验问题,这个时候我们可以使用contain-intrinsic-size
来确保元素的正确渲染,同时也保留延迟渲染的好处。
contain-intrinsic-size
是与content-visibility
配套使用的属性,它可以用来控制由content-visibility
指定的元素自然大小
语法
此属性是以下 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
并且在非可视区的元素是否存在于可访问树中?
从这个搜索中我们可以看出,content-visibility: auto
非可视区内的内容在文档对象模型中仍然可用,并且在可访问性树中(与visibility: hidden
不同)。
能否用来做图片懒加载?
我们以上面的例子插入一些不同的图片来看看非可视区的图片资源到底会不会加载?
从Network中来看,即便这些可视区外的内容没有被渲染,但它们的一些静态资源仍然会被加载。这样看来content-visibility: auto
并不适合用来做图片懒加载。
兼容性
content-visibility是chrome85新增的特性,所以兼容性还不是很高,
目前来看,content-visibility
还不适合用于实际业务中,但它是一个非常实用的CSS属性,相信兼容性的问题在不久的将来会得到解决~
喜欢的同学欢迎点个赞呀~ 欢迎大家关注公众号 「前端南玖」,如果你想进前端交流群一起学习,请点这里
我是南玖,我们下期见!!!
两行CSS让页面提升了近7倍渲染性能!的更多相关文章
- 我是如何将一个老系统的kafka消费者服务的性能提升近百倍的
☞☞☞ 我是如何将一个老系统的kafka消费者服务的性能提升近百倍的 ☜☜☜ ○○○○○○○○○○○○○○○ 大家好,又见面了~ kafka作为一种高吞吐量的分布式发布订阅消息系统,在业务系统中被广泛 ...
- HTML与CSS简单页面效果实例
本篇博客实现一个HTML与CSS简单页面效果实例 index.html <!DOCTYPE html> <html> <head> <meta charset ...
- web前端学习(三)css学习笔记部分(5)-- CSS动画--页面特效、HTML与CSS3简单页面效果实例
CSS动画--页面特效部分内容目前仅仅观看了解内容,记录简单笔记,之后工作了进行内容的补充 7. CSS动画--页面特效 7.1 2D.3D转换 7.1.1 通过CSS3转换,我们能够对元素进行 ...
- 用 CSS 隐藏页面元素
用 CSS 隐藏页面元素有许多种方法.你可以将 opacity 设为 0 将 visibility 设为 hidden 将 display 设为 none 将 position 设为 absolute ...
- Flex中使用CSS控制页面样式
Using file: Stylebounding.mxml Stylebounding2.mxml myCSS0329.css 在Flex4中使用CSS控制样式,既可以直接在MXML文件中写样式,也 ...
- 用 CSS 隐藏页面元素的 5 种方法
原文链接:用 CSS 隐藏页面元素的 5 种方法,转载请注明来源! 用 CSS 隐藏页面元素有许多种方法.你可以将 opacity 设为 0.将 visibility 设为 hidden.将 disp ...
- CSS排版页面
创建CSS文件如下: @charset "utf-8"; /* CSS Document */ *{ margin:0px; padding:0px; border:0px; } ...
- css 实现页面加载中等待效果
<!DOCTYPE html> <html> <head> <title>css实现页面加载中,请稍候效果</title> <meta ...
- 《Two Days DIV + CSS》读书笔记——CSS控制页面方式
1.1 你必须知道的知识 (其中包括1.1.1 DIV + CSS的叫法解释:1.1.2 DIV + CSS 名字的误区:以及1.1.3 W3C简介.由于只是背景知识,跳过该章.) 1.2 你必须掌握 ...
- CSS 隐藏页面元素的 几 种方法总结
用 CSS 隐藏页面元素有许多种方法.你可以将 opacity 设为 0.将 visibility 设为 hidden.将 display 设为 none 或者将 position 设为 absolu ...
随机推荐
- git 密码修改
当由于修改了Git 的密码导致 pull 等操作报错时,比如报以下错误: fatal: Authentication failed for 'http://xxxxxxxxxxxxxxxxxx.git ...
- Filebeat Nginx Module 自定义字段
Filebeat Nginx Module 自定义字段 一.修改/usr/local/nginx/conf/nginx.conf中 log_format access '$remote_addr - ...
- 谣言检测——(GCAN)《GCAN: Graph-aware Co-Attention Networks for Explainable Fake News Detection on Social Media》
论文信息 论文标题:GCAN: Graph-aware Co-Attention Networks for Explainable Fake News Detection on Social Medi ...
- Dockerfile中ADD命令详细解读
ADD指令的功能是将主机构建环境(上下文)目录中的文件和目录.以及一个URL标记的文件 拷贝到镜像中. 其格式是: ADD 源路径 目标路径 #test FROM ubuntu MAINTAINER ...
- 9. Ceph 基础篇 - Crush Maps
文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247485302&idx=1&sn=00a3a204 ...
- 创建多个节点的集群 - Elastic Stack 8.0
文章转载自:https://mp.weixin.qq.com/s/k6u9Q2nebW9qgZMghQwJng 详述如何安装3个节点的 Elasticsearch 集群.我将使用 Docker 来进行 ...
- Elasticsearch:top_hits aggregation
top_hits指标聚合器跟踪要聚合的最相关文档. 该聚合器旨在用作子聚合器,以便可以按存储分区汇总最匹配的文档. top_hits聚合器可以有效地用于通过存储桶聚合器按某些字段对结果集进行分组. 一 ...
- Redis 监控指标
监控指标 性能指标:Performance 内存指标: Memory 基本活动指标:Basic activity 持久性指标: Persistence 错误指标:Error 性能指标:Performa ...
- SkyWalking 6.x 的架构图
可以看到主要由四部分组成: Agent(也叫Probe):代理或者探针,集成在被监测的应用中(SDK形式或者动态注入),采集应用的数据发送给后端(OAP). UI:自带的Web页面. OAP:后端,接 ...
- nginx+gunicorn部署Django项目
实际采用的nginx.conf文件内容: server { charset utf-8; listen 80; server_name ip; access_log /webapps/project/ ...