I am not sure If I get your question right but in case 1, when the parser is starts executing the script, the DOMContentLoaded is not fired yet and it is still parsing rest of the document. Meanwhile you call focus
on the elemB
, you are immediately triggering the layout flow.
In case 2, onClick
function is not called at all unless you click the document itself. You can verify this by turning on the "Paint Flashing" on the fiddle you provided. The input will become green only when you click.
Whereas in the first case you see a brief flash of the input at start (thats your call to .focus) and then the whole documentElement (at DOMContentLoaded).
In case two you only have the whole documentElement flash once (on DOMContentLoaded, provided that nothing else trigger reflow/repaint onload event) and then only the input element once per click.
PS:
Now as far as I can see, I have tried your 2 cases on my local machine and interestingly in your first case I see 2 layout activites right after DOMContentLoaded.
However if I comment out the line elementB.focus();
from your case 1 and record again, I see 2 layout activities again.
From my understanding the browser will do 2 layout operations on start, once it starts to parse the body and then once around DOMContentLoaded. And if any synchronous forced layout trashing is done by javascript (by calling any of the methods/properties listed in your link), the browser will try to batch these operations.
To test this behavior, I modified your 1st case as below:
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text" style="position:relative;top:0px;">
<script type="text/javascript">
var elementB = document.querySelector('input');
elementB.focus();
</script>
<script async="true">
setTimeout(function(){
elementB.style.top = parseInt(elementB.style.top) + 5 + "px";
},500)
</script>
</body>
</html>
Now what will happen is, you will have a third layout activity right after (~500ms) the load event (async is unnecessary). But if you were to make the setTİmeout 0ms, you would get 2 layout activities again! (the microtask queue behavior might not be guaranteed, in case you see 3 layouts, to force sync layout, remove the async attribute and the setTimeout wrap inside the 2nd script tag). Bottom Line: So the browser batches it, or at least this is what I see from this example.
For your second case, when I record it the way you posted, it is correct that I do not see layout activity (2 layout as before). But what I see is a consistent style recalculation + update layout tree + painting after each event. This makes me think that once the layout tree is updated, if layout trashing is not necessary it is not recalculated. To test that behavior, I changed your second script as below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="text" style="position:relative;top:0px;">
<script type="text/javascript">
var elementB = document.querySelector('input');
function onClick() {
elementB.focus();
elementB.style.top = parseInt(elementB.style.top) + 5 + "px";
}
document.addEventListener('click', onClick);
</script>
</body>
</html>
Here each time you click the document, the input box will move down 5 pixels. If you record during 10 seconds for multiple click events you will see a lot of update layout tree + repaint AND layout trashing as well. This makes me think layout trashing is done after updating layout tree if only necessary.
CONCLUSION (I might be terribly wrong)
- The browser will try to batch layout activity during parsing of the HTML.
- element.focus will trigger repaint + update layout tree, but layout trashing is not guaranteed (at least from these examples)