为啥我在更改和检索元素位置时看不到布局/重排被触发?

Posted

技术标签:

【中文标题】为啥我在更改和检索元素位置时看不到布局/重排被触发?【英文标题】:Why don't I see layout/reflow being triggered when changing and retrieving element positions?为什么我在更改和检索元素位置时看不到布局/重排被触发? 【发布时间】:2021-10-21 11:10:06 【问题描述】:

我一直在尝试详细了解何时使用 Chrome 开发工具触发布局/重排。我在 JSFiddle 中设置了这个简单的示例,我在 for 循环中一次更改一组 div 的“左”位置。然后,我立即检查“left”属性,我理解它应该强制布局(因为浏览器必须重新计算元素的位置才能提供更新的值):

javascript

const colors = document.body.querySelectorAll("div") 

const button = document.querySelector(".my-button")
button.onclick = handleClick

function handleClick () 
 colors.forEach(color => 
    color.style["left"] = "50px"
    const left = color.style["left"]   <--- This should force a Layout since "left" was just updated
 )  

html

<html>
  <head>
  </head>
  <body>
    <button class="my-button">
      Click
    </button>
    <div class="red-color">
      red
    </div>
    <div class="blue-color">
     blue
    </div>
    <div class="green-color">
      green
    </div>
    <div class="yellow-color">
      yellow
    </div>
    <div class="black-color">
      black
    </div>
  </body>
</html>

CSS:

div 
  position: relative

在开发工具中,我希望看到在 for 循环的每次迭代中都会触发一个布局。具体来说,我正在寻找黄色的函数调用栏(应该对应于 handleClick 回调)下方的紫色布局栏(每次迭代一个)。相反,它看起来像在调用 handleClick 之后发生了一个 Layout:

以下是我的问题:

当我在处理 div 元素的位置并立即检查它们的新位置时,为什么在 handleClick 期间看不到任何布局被触发? 我是否应该期望看到在 for 循环的每次迭代中都会触发一个新布局?我会假设是这样,因为浏览器需要在每次迭代时提供更新的“左”位置。

【问题讨论】:

奇怪,也许这是 v8 的某种优化。我设法通过在每次迭代之间等待一些毫秒来触发回流:jsfiddle.net/apz3gLjh 【参考方案1】:

检查Element.style.property 值不会触发回流号。该值不是“计算值”,不需要重新计算布局。

const target = document.querySelector(".target");

target.style.left = "0px";

// logs "0px"
// even though the real computed value is "25px"
// from the !important rule in CSS
console.log( target.style.left );

target.classList.remove("begin");
target.style.left = "250px";
// now the computed style is correctly 250px
// but since we didn't trigger a reflow
// the transition doesn't kick in
.target 
  transition: left 2s;
  width: 50px;
  height: 50px;
  background: salmon;
  position: absolute;

.begin 
  /* will take precedence over the .style rule */
  left: 25px !important;
&lt;div class="target begin"&gt;&lt;/div&gt;

也许你把它和getComputedStyle(element).property混淆了,这会导致回流:

const target = document.querySelector(".target");

target.style.left = "0px";
// this triggers a reflow, the transition will kick in
console.log( getComputedStyle(target).left );
target.style.left = "250px";
.target 
  transition: left 2s;
  width: 50px;
  height: 50px;
  background: salmon;
  position: absolute;
&lt;div class="target"&gt;&lt;/div&gt;

【讨论】:

以上是关于为啥我在更改和检索元素位置时看不到布局/重排被触发?的主要内容,如果未能解决你的问题,请参考以下文章

页面重绘重排

重排和回流

整理涵盖很全很广的前端知识点

DOM 元素布局更改事件

为啥设置 textContent 会触发重排?

回调中未触发回流/布局?