While the information has already been shared in the comments of other answers, here is a comprehensive list of triggers. It's important to note that for getters like elem.offsetWidth
, wrapping it in a function call is unnecessary. The getter will be invoked regardless, and bypassing it could lead to serious issues if an optimization attempt were made.
Reflow should be used judiciously as it can have negative repercussions if misused.
To grasp the concept of reflow and its necessity in this context, I recommend reading through this answer along with related responses. In essence, the browser delays recalculating CSSOM boxes and styles until the last moment, thus only recognizing the final state when a transition is applied while overlooking any temporary removals. Initiating a synchronous reflow compels the CSSOM to reassess all page elements, acknowledging the absence of the transition set initially, thereby preparing for its subsequent application.
A reflow entails recalculating all document elements, which can significantly burden computational resources. When used iteratively or within intricate DOM layouts, it may severely impact overall page performance.
For transitioning effects, leverage the Web Animations API
This API, though absent in 2014, has been supported across modern browsers for years now. By interfacing directly with the animation engine where CSSOM manages animations and transitions, the Web Animations API eliminates the need for convoluted DOM manipulation pathways.
This method streamlines style recalculations, offers JavaScript-friendly functionalities, and provides clear Promises for smooth event handling, surpassing the complexities associated with numerous CSS animation-x
events.
To replicate OP's fiddle using the Web Animations API, follow these simple steps:
function makeAnimation()
{
const ul = document.getElementsByTagName('ul')[0];
ul.animate(
[ // Keyframes defining the animation/transition
{ left: "-600px", },
{ left: "-0px", }
],
{ duration: 200/* ms */, easing: "ease-out" }
);
}
.viewport { width: 600px; height: 300px; }
ul { list-style: none; margin: 0; padding: 0; position: relative; width: 250%; }
ul li { display: block; float: left; width: 600px; height: 300px; line-height: 300px; font-size: 30px; text-align: center; }
<div class="viewport">
<ul>
<li style="background: lightblue; color: red">1</li>
<li style="background:gray; color: black;">2</li>
</ul>
</div>
<button onclick="makeAnimation()">Make animation</button>
If triggering a reflow becomes imperative...
Although this topic warrants a separate Q/A session, consolidating all reflow triggers into a single phase and ensuring no interference with the box model is crucial. This demands meticulous control over DOM modifications to prevent disruptions. Essentially, during any point in the Event-Loop sequence, refrain from invoking any triggers (as some can be stealthy) after making your intended adjustments to the DOM.
Instead, await the subsequent ResizeObserver callback. These callbacks execute post-browser recalculation (specs, step 16), meaning that by delaying until this stage and then calling elem.offsetWidth
, the browser caches the data, eliminating the need for further recalculation & reflows. However, maintaining DOM integrity throughout this process is paramount. A viable approach involves employing a two-phase handler within ResizeObserver callbacks—initially gathering computed values followed by executing DOM manipulations based on these computations.
This approach typically limits reflows to just two per frame (one triggered by the browser and one by custom scripts). Even with thorough knowledge of reflow triggers, unexpected occurrences like those induced by scrollTo()
, which combines reflow initiation with box alterations beyond user intervention, can pose challenges...