v153 · html · event loop
transitionrun and media query change, on time
The HTML rendering steps run in a fixed order, and two of them fire the events this change is about. Blink was dispatching both a beat late — a transition started earlier in the same rendering iteration had to wait for the next one. Chrome 153 puts them where the specification says, which is where Gecko and WebKit already had them.
concepts
-
How many frames until it runs
Start a transition from a task, a microtask, an animation frame callback, a scroll handler and a media query listener, and count the rendering frames before
transitionrunarrives. The trigger point is the whole story. -
One rendering iteration, in order
Resize a frame and record what happens next: the media query
change, the transition events, the animation frame callback, in the order the browser actually produced them — with the specification's step numbers beside them. -
A layout that animates on a breakpoint
The shape that makes the delay visible: a media query listener that starts an animation. Drag the width and watch the measured lag between crossing the breakpoint and the animation beginning.
why it shipped
"Update the rendering" is a numbered list. Media query changes are reported at one step, animations are updated and their events sent at a later one, and animation frame callbacks run after that. A transition created during an earlier step of an iteration should therefore have its transitionrun dispatched in that same iteration, at the animation step.
Blink deferred it instead, so a transition started from a media query listener did not announce itself until the following iteration. One frame is not much on its own; it is enough for code that coordinates two animations, or that waits for transitionrun before measuring, to behave differently in Chrome than in Firefox and Safari. Interoperability is the whole feature — there is no new API here, only agreement about when.
the steps involved
// From HTML's "update the rendering", in order:
// …
// evaluate media queries and report changes ← mql change fires here
// update animations and send events ← transitionrun fires here
// …
// run the animation frame callbacks ← requestAnimationFrame runs here
// update the rendering or user interface
mql.addEventListener("change", () => {
panel.classList.add("open"); // creates a transition, during an earlier step
});
// The spec says transitionrun is dispatched later in THIS iteration.
// Blink used to dispatch it in the next one.
enabling it now
You cannot. There is no flag for this one: it is a change to when Blink dispatches two existing events, not a feature that can be switched on, and --enable-experimental-web-platform-features was measured making no difference to it.
So the demos here measure the state a browser is in rather than offering a comparison. On the Chrome 150 used to build them, a transition started from a media query change listener saw transitionrun one rendering iteration later than the specification allows, and one started from a scroll handler did too — while transitions started from a microtask or an animation frame callback arrived at the first opportunity. That is exactly the shape of the bug being fixed, and on Chrome 153 the same pages should read first opportunity across the board.