重绘重排、CSS树DOM树渲染树、动画加速 ✅

news/2024/11/25 19:28:16/

浏览器下载完页面中的所有组件,HTML标记、JavaScript、CSS、图片后,之后会解析并生成两个内部数据结构:DOM树和渲染树。DOM树表示页面结构,渲染树表示DOM节点如何显示。
——《高性能JavaScript》

DOM树中的每一个需要显示的节点在渲染树中至少要存在一个对应的节点 (display为none的元素仍然存在于DOM树里面,你在控制台里面就能看见它,但是他并不存在于渲染树中;但是opacity为0的元素和visibility为hidden的元素虽然在屏幕上不可见,但是仍然存在于渲染树中,因为仍然在文档流中占有位置)


DOM树&CSS树&渲染树

在DOM树和CSS树均构建完成后,浏览器会将它们结合起来生成渲染树。每个可见元素会在渲染树中对应一个节点,并且会包含与该元素相关的样式信息。
在渲染树构建完成后,浏览器会进行第一次绘制(Render)。这时,浏览器会将渲染树中的节点绘制为屏幕上的像素,也就是最终可视化的内容。
需要注意的是,CSS Tree的构建并不会阻塞DOM Tree的构建。当浏览器接收到HTML文档时,它会开始解析HTML并构建DOM树。同时,如果遇到外部CSS文件(例如通过link标签引入)或者内联CSS(通过style标签),浏览器会开始解析这些CSS内容以构建CSS树。在这种情况下,DOM树和CSS树的构建可以并行进行,直到浏览器需要应用样式时。但是如果css文件是通过script标签加载的 (应该行得通吧,我也没试过),默认情况下script标签会阻塞后续html代码的执行,此时可以认为“CSS Tree的构建阻塞了DOM Tree的构建”。如果我的css文件通过script来引入,但是script上存在defer属性,是否可以理解为“DOM Tree的构建阻塞了CSS Tree”?


重排&重绘

当DOM的变化影响了元素的集合属性(宽和高),浏览器需要重新计算元素的集合属性,同样其他元素的集合属性和位置也会受到影响,浏览器这个重新绘制的过程就是重排,完成重排后浏览器会重新绘制收到影响的部分到屏幕中,即重绘。

以下属性的改变可能会造成重排:height、width、margin、padding、border、position、top、left、right、bottom、display、visibility、font-size、font-family……

Q:为什么字体的大小和样式会造成重排?
A:可能会撑开容器的宽高

Q:绝对定位的元素脱离了文档流,为什么他们的left和top等属性被修改也会重排?
A:它的新位置需要根据其包含块重新计算,而且可能存在与其他元素的重叠。暂时只想到这么多

还有一些你“不经意间的操作”也会造成重排

  • 浏览器窗口尺寸的改变
  • 添加或删除可见的DOM元素
  • 通过JavaScript获取元素的offsetTop、scrollTop、clientTop、currentStyle等属性(浏览器对视图的更新“并不是实时的”,大多数浏览器通过队列化修改并批量执行来优化重排过程,如果通过Js获取元素的这些样式信息,浏览器会强刷新队列并要求计划任务立即执行,以获取最新的最准确的值)。

最小化重排与重绘

1、批量修改样式

比如可以把:

el.style.height = '1px'
el.style.margin = '2px'
el.style.padding = '3px'

修改为:

el.style = "height: 1px; margin: 2px; padding: 3px"

2、批量修改DOM

当需要对DOM元素进行一系列操作的时候,可以通过以下步骤来减少重排和重绘:

  1. 让元素脱离文档流(用得最多的是绝对定位、相对定位、浮动和设置display为none)
  2. 修改元素样式
  3. 让元素回归文档流

这里会触发重绘和重排的只有步骤1和步骤3。

上面这段分析来自《高性能JavaScript》。
一般情况下让元素脱离文档流(如设置为绝对定位),再修改他的样式,并不会直接影响其他元素的重排,因为他不再占据正常文档流的空间。其他情况确实没遇见过
但是当元素脱离了渲染树,那他的样式的改变确实就不会造成重排。所以可以设置display为none,以实现步骤1。

3、使用transform来代替left和top

先介绍一下合成层:现代浏览器中用于渲染的一个重要概念。它是一个独立的图层,用于将元素组合到一起以高效地进行绘制和显示。云里雾里的
合成层可以独立于原始文档流和元素的布局进行操作,允许浏览器在不影响其他元素的情况下进行更复杂的渲染处理。而且合成层的创建利用了图形处理单元(GPU)的能力来加速渲染。这使得元素能够以更高的性能进行动画和变换,尤其是在平移、缩放和旋转等操作时表现得尤为明显。
因为合成层可以独立处理,当在该层上的元素发生变化时(如位置、透明度等),浏览器只需重新绘制这个合成层,而不需要重新计算和更新整个文档流。这种方式可以显著提高网页的渲染效率,尤其是对于频繁更新的动画效果。 当使用 CSS transform 属性(如 translate)来移动元素时,浏览器会将该元素提升到一个新的合成层中。这意味着,浏览器可以独立于主布局流程处理这个元素,减少重新计算布局的次数
所以可以认为:使用 transform 修改偏移量不会引起重排,因为它不会影响文档流中的其他元素的位置和布局。


动画加速

在CSS中启用动画加速,通常是通过使用硬件加速的技术实现的,动画加速本质上是触发了合成层
可以通过以下属性来开启动画加速:

  • 使用transform:通过改变元素的变换属性(如 translate、scale、rotate 等),浏览器可以将该元素提升到合成层,使用GPU渲染,从而实现更平滑的动画效果。

    css">.animated {transition: transform 0.3s ease;
    }
    .animated:hover {transform: translateX(10px); /* 触发硬件加速 */
    }
    
  • 通过opacity:更改元素的不透明度(opacity)也能够触发合成层,从而启用硬件加速。

    css">.fade-in {transition: opacity 0.5s ease;opacity: 0;
    }
    .fade-in.visible {opacity: 1; /* 触发硬件加速 */
    }
    
  • 避免重排属性:如果动画涉及到会引起重排(reflow)的属性,如 width、height、margin 等,应尽量避免使用这些属性来做动画,因为这会增加性能开销并影响流畅度。

  • 使用will-change:通过CSS的 will-change 属性,开发者可以显式告诉浏览器某个元素即将发生变化。这样,浏览器可以提前进行优化,创建合成层。(没用过这玩意,can i use上提示有兼容性问题?)

但是,硬件加速可能会造成内存占用的增加,当通过 transform 或 opacity 创建合成层时,浏览器会为这些元素分配更多的内存。而且如果每个动画元素都使用合成层,可能会导致GPU负担过重,导致整体性能下降,尤其是在低性能设备上。
此外,还存在一些兼容性问题 (没遇到过)


文章内容很多参考了《高性能JavaScript》。


http://www.ppmy.cn/news/1549890.html

相关文章

OAI-5G开源通信平台实践(五)

参考资料及进阶学习 open5GS 以下为基于oai 5GC + oai gnb + nrue rfsim 在docker中的搭建流程 ci-scripts/yaml_files/5g_rfsimulator develop oai / openairinterface5G GitLab (eurecom.fr) 多UE运行 https://github.com/EpiSci/oai-lte-5g-multi-ue-proxy L2 sim…

【SQL】【数据库】语句翻译例题

SQL自然语言到SQL翻译知识点 以下是将自然语言转化为SQL语句的所有相关知识点,分门别类详细列出,并结合技巧说明。 1. 数据库操作 创建数据库 自然语言:创建一个名为“TestDB”的数据库。 CREATE DATABASE TestDB;技巧:识别**“创…

C51数字时钟/日历---LCD1602液晶显示屏

题目要求: 数字电子日历/时钟设计 设计一个基于MCS51的电子日历和时钟。 基本要求 (1) 可通过按键在日历和时间之间切换显示; (2) 可由按键调整日期和时间 (3) 可整点报时&#x…

docker pull命令拉取镜像失败的解决方案

docker pull命令拉取镜像失败的解决方案 简介: docker pull命令拉取镜像失败的解决方案 docker pull命令拉取镜像失败的解决方案 一、执行docker pull命令,拉取镜像失败 报错信息:error pulling image configuration: Get https://produc…

Linux-Nginx虚拟主机

文章目录 虚拟主机路由规则 🏡作者主页:点击! 🤖Linux专栏:点击! ⏰️创作时间:2024年11月21日9点32分 虚拟主机 配置不同域名不同端口号访问到不同内容 mkdir /data/nginx{1..3} #创建三个…

SpringBoot3中的性能提升介绍

Spring Boot 3 是对 Spring Boot 框架的一个重要更新版本,它延续了 Spring Boot 简化 Spring 应用程序开发的宗旨,同时进一步提升了开发者体验和应用程序性能。本文将详细介绍 Spring Boot 3 中性能优化的提升,包括具体的代码示例&#xff0c…

PySpark3:pyspark.sql.functions常见的60个函数

目录 一、常见的60个函数 1、col 2、lit 3、sum 4、avg/mean 5、count 6、max 7、min 8、concat 9、substring 10、lower 11、upper 12、trim 13、ltrim 14、rtrim 15、split 16、explode 17、collect_list 18、collect_set 19、asc 20、desc 21、when 2…

ESP8266 AP模式TCP服务器 电脑手机网络调试助手

AP模式TCP服务器和手机电脑网络调试助手多连接