javascriptgoogle-chrome-devtoolsreflow

Why don't I see layout/reflow being triggered when changing and retrieving element positions?


I've been trying to learn more about when layout/reflow gets triggered using Chrome Dev Tools. I have this simple example set up in JSFiddle, where I am changing the "left" position of a group of divs one at a time in a for loop. Then, I'm immediately checking the "left" property, which I understand should force a layout (since the browser must recompute the position of the element in order to provide the updated value):

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
}

In the dev tools, I was expecting to see that on each iteration of the for loop, a layout would be triggered. Specifically, I was looking out for purple Layout bars (one for each iteration) to be under the yellow Function Call bar (which should correspond to the handleClick callback). Instead, it looks like there's a single Layout that occurs after handleClick is called: enter image description here

Here are the questions I have:


Solution

  • Checking the Element.style.property value will not trigger a reflow no. This value is not the "computed value", and this doesn't require the layout to be recalculated.

    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;
    }
    <div class="target begin"></div>

    Maybe you were confusing it with getComputedStyle(element).property which will cause a reflow:

    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;
    }
    <div class="target"></div>