当前位置:网站首页>web 应用开发最佳实践之一:避免大型、复杂的布局和布局抖动
web 应用开发最佳实践之一:避免大型、复杂的布局和布局抖动
2022-08-04 19:51:00 【华为云】
布局是浏览器计算元素几何信息的地方:即元素在页面中的大小和位置。 每个元素都将具有基于所使用的 CSS、元素的内容或父元素的显式或隐式大小信息。 该过程在 Chrome、Opera、Safari 和 Internet Explorer 中称为布局(Layout).
在 Firefox 中,它被称为回流(reflow),但实际上过程是相同的。
与样式计算类似,布局成本的直接关注点是:
- 需要布局的元素数量。
- 这些布局的复杂性。
简而言之:
- 布局通常限定于整个文档。
- DOM 元素的数量会影响性能; 你应该尽可能避免触发布局。
- 评估布局模型性能; 新的 Flexbox 通常比旧的 Flexbox 或基于浮动的布局模型更快。
- 避免强制同步布局和布局抖动; 读取样式值然后进行样式更改。
Avoid layout wherever possible
当您更改样式时,浏览器会检查是否有任何更改需要计算布局,以及是否需要更新渲染树。 更改“几何属性”,例如宽度、高度、左侧或顶部都需要执行布局过程。
.box { width: 20px; height: 20px;}/** * Changing width and height * triggers layout. */.box--expanded { width: 200px; height: 350px;}
布局几乎总是作用于整个文档。 如果您有很多元素,则需要很长时间才能弄清楚它们的位置和尺寸。
如果无法避免布局,那么关键是再次使用 Chrome DevTools 来查看需要多长时间,并确定布局是否是造成瓶颈的原因。 首先,打开 DevTools,转到 Timeline 选项卡,点击记录并与您的站点进行交互。 当您停止录制时,您会看到您的网站表现的细分:
在上例中深入研究帧时,我们看到在布局内部花费了超过 20 毫秒,当我们有 16 毫秒在动画中在屏幕上显示帧时,这太高了。 您还可以看到 DevTools 会告诉您树的大小(在本例中为 1,618 个元素),以及需要布局的节点数量。
Avoid forced synchronous layouts
将网页运送到屏幕具有以下顺序:
首先运行 JavaScript,然后是样式计算,然后是布局。 但是,可以使用 JavaScript 强制浏览器提前执行布局。 它被称为强制同步布局。
首先要记住的是,当 JavaScript 运行时,前一帧中的所有旧布局值都是已知的,可供您查询。 因此,例如,如果您想在帧的开头写出元素的高度(让我们称其为“框”),您可以编写如下代码:
// Schedule our function to run at the start of the frame.requestAnimationFrame(logBoxHeight);function logBoxHeight() { // Gets the height of the box in pixels and logs it out. console.log(box.offsetHeight);}
如果你在询问高度之前改变了盒子的样式,事情就会变得有问题:
function logBoxHeight() { box.classList.add('super-big'); // Gets the height of the box in pixels // and logs it out. console.log(box.offsetHeight);}
现在,为了回答高度问题,浏览器必须先应用样式更改(因为添加了超大类),然后运行布局。 只有这样,它才能返回正确的高度。 这是不必要的并且可能是昂贵的工作。
因此,您应该始终批量读取样式并首先执行(浏览器可以使用前一帧的布局值),然后执行任何写入:
正确完成上述功能将是:
function logBoxHeight() { // Gets the height of the box in pixels // and logs it out. console.log(box.offsetHeight); box.classList.add('super-big');}
在大多数情况下,您不需要应用样式然后查询值; 使用最后一帧的值就足够了。 同步运行样式计算和布局并早于浏览器的预期是潜在的瓶颈,而不是您通常想要做的事情。
Avoid layout thrashing
有一种方法可以使强制同步布局变得更糟:快速连续地进行大量布局。 看看这段代码:
function resizeAllParagraphsToMatchBlockWidth() { // Puts the browser into a read-write-read-write cycle. for (var i = 0; i < paragraphs.length; i++) { paragraphs[i].style.width = box.offsetWidth + 'px'; }}
此代码遍历一组段落并设置每个段落的宽度以匹配名为“box”的元素的宽度。 它看起来无害,但问题是循环的每次迭代都会读取一个样式值(box.offsetWidth),然后立即使用它来更新段落的宽度(paragraphs[i].style.width)。 在循环的下一次迭代中,浏览器必须考虑自上次请求 offsetWidth(在前一次迭代中)以来样式已更改的事实,因此它必须应用样式更改并运行布局。 这将在每次迭代中发生!。
此示例的修复方法是再次读取然后写入值:
// Read.var width = box.offsetWidth;function resizeAllParagraphsToMatchBlockWidth() { for (var i = 0; i < paragraphs.length; i++) { // Now write. paragraphs[i].style.width = width + 'px'; }}
边栏推荐
猜你喜欢
ELECTRA: Pre-training Text Encoders as Discriminators Rather Than Generators
Tensorflow2 环境搭建
阿里的arthas使用,入门报错:Unable to attach to 32-bit process running under WOW64
【AGC】构建服务1-云函数示例
二叉树的遍历
SIGIR 2022 | 邻域建模Graph-Masked Transformer,显著提高CTR预测性能
Ant Group's time series database CeresDB is officially open source
Jmeter - Heap配置原因报错Invalid initial heap size: -Xms1024m -Xmx2048mError
Infrared image filtering
基于HDF的LED驱动程序开发(2)
随机推荐
Storage resource activation system to help new infrastructure
The Development and Current Situation of Object Detection
力扣题(5)—— 最长回文子串
JSD-2204-酷莎商城(管理员模块)-密码加密-Day10
成品升级程序
运维就业现状怎么样?技能要求高吗?
NLP技术为何在工业界这么卷?前沿案例解析来了
华为WLAN技术:AP上线及相关模板的配置实验
刷题-洛谷-P1179 数字统计
性能测试流程
The establishment of simple data cache layer
June To -.-- -..- -
PostgreSQL的 SPI_接口函数
c sqlite...
Query the published version records of the APP Store
七夕福利!中奖名单:书籍免费送!
刷题-洛谷-P1307 数字反转
Finger Vein Recognition-matlab
IIC驱动OLED
Ant Group's time series database CeresDB is officially open source