← Chrome 153 reference

v153 · enabled by default · css · events

Interoperable dispatch timing for transitionrun and media query events

Limited availability (behavior alignment)

  • Chrome · behavior change from 153
  • Edge · follows Chromium
  • Firefox · already conformant (per listing)
  • Safari · already conformant (per listing)

This is a behavior-alignment change, not a new API: the transitionrun and media-query change events themselves are long-established (BCD records transitionrun_event since Chrome 74 / Firefox 53 / Safari 13.1, and MediaQueryList change_event since Chrome 39 / Firefox 55 / Safari 14). Chrome 153 changes when they fire inside the rendering steps, aligning Blink with the HTML event loop processing model and — per the ChromeStatus API record — “making the timing interoperable with Gecko and WebKit”. No webstatus.dev entry exists for the timing change itself (zero matches, 2026-07-29); BCD does not record dispatch-timing behavior.

A conformance fix that moves two event dispatches to their spec-defined points in the rendering steps: media-query change events now fire at the media-query evaluation step (CSSOM View — evaluate media queries and report changes), before any pending animation events; and transitionrun events fire at the animation-events step (Web Animations — update animations and send events) in the same rendering iteration even for transitions created earlier in that iteration — instead of a frame late.

Behavior change — event ordering observable by scripts

Scripts that implicitly depended on the old Blink timing — for example asserting that transitionrun arrives one frame after a style change that creates a transition, or observing media-query change listeners interleaved with transitionrun/animationstart listeners in a single callback batch — will observe a different, now spec-conformant order from Chrome 153. Review tests that snapshot event order. There is no new API surface to feature-detect; the events, their interfaces, and their targets are unchanged.

Source-dated flag state. The milestone=153 listing files this as “Enabled by default”. As of 2026-10-08, EventTimingMatchingHTML is status: "stable" on trunk, but remains status: "experimental" on the M153 branch (7978). Neither record marks it public: true; the Blink command-line switch, not a documented chrome://flags entry, is the reproducible way to compare behaviors in a local build: --enable-blink-features=EventTimingMatchingHTML versus --disable-blink-features=EventTimingMatchingHTML. The later trunk flip alone does not establish the M153 build default.

at a glance

What it isA Blink conformance change to when two existing events dispatch during the event loop's rendering steps — media-query change (MDN) and transitionrun (MDN) — aligning Chrome with the HTML event loop specification and with Gecko/WebKit
Milestone listingChrome 153 — Enabled by default (listing, verified 2026-07-29)
New API surfaceNone — no new interfaces, members, values, or flags for authors
What changes(1) transitionrun fires in the same rendering iteration that creates the transition (previously delayed to a later iteration); (2) media-query change fires at the media-query step, before pending animation events (previously intermixed with them)
Runtime featureEventTimingMatchingHTML: stable on trunk, experimental on M153 branch (2026-10-08); neither publicly exposed as a flags-UI toggle
ImplementationCL 8044688 (merged 2026-07-08) + CL 8045604 (merged 2026-07-14), both in page_animator.cc; tracking bug crbug.com/397737222
ChromeStatus6312504658624512 — Interoperable dispatch timing for transitionrun and media query events (Blink component Blink>Animation)
Source: chromestatus.com/feature/6312504658624512; CL 8044688; CL 8045604

why it exists

The ChromeStatus record states the motivation verbatim:

“Aligns Blink's dispatch timing for animation “transitionrun” event and media query “change” event with the spec, making the timing interoperable with Gecko and WebKit. More precisely, as per HTML window event loop specification, “transitionrun” events will be fired at Step 3.11 even for animations created earlier in the same iteration (instead of delaying them for a later iteration), and the media query “change” event will be fired at Step 3.10 before firing any pending animation events (instead of intermixing them with animation events at Step 3.11).”

Two long-standing Blink deviations are being removed:

Both deviations made cross-browser test assertions and framework scheduling code order-dependent in ways that differed per engine; the listing frames the fix as an interoperability change. (The listing’s “Step 3.10/3.11” numbering refers to the update the rendering sub-steps of the event loop processing model; the step names are quoted below because numbering shifts as steps are added.)

Source: ChromeStatus API record (summary quoted verbatim); HTML — event loop processing model

the spec order: where each event belongs

The update the rendering steps of the HTML event loop run, in order (relevant steps quoted verbatim from the processing model, fetched 2026-07-29):

  1. … run the resize steps for doc [CSSOM View]
  2. … run the scroll steps for doc [CSSOM View]
  3. … evaluate media queries and report changes for doc [CSSOM View] — the media-query step (listing “3.10”)
  4. … update animations and send events for doc [Web Animations] — the animation-events step (listing “3.11”)
  5. … run the fullscreen steps, canvas context-lost steps, and then the animation frame callbacks (requestAnimationFrame)

Two consequences follow from the spec text itself:

Source: HTML — event loop processing model; CSSOM View — evaluate media queries and report changes; Web Animations — update animations and send events

behavior contract 1: transitionrun in the creating iteration

CSS Transitions 2 §5.1 dispatches transition events by comparing the transition’s phase “in the previous animation frame to its current state”; the phase table maps idle → pending or before to transitionrun (elapsed time = interval start), with the target being “the transition’s owning element”. The event marks the moment a transition first leaves the idle phase — before any transition-delay has begun.

SituationBefore Chrome 153 (Blink)From Chrome 153 (spec-aligned)
Transition created by a style change during iteration Ntransitionrun dispatched in a later rendering iteration (frame late)transitionrun dispatched in iteration N’s animation-events step (“update animations and send events”)
Listener mutates the animation it just observedMutation lands one frame later than the event queue impliesListener runs in the same frame; its mutations apply to the current iteration’s rendering
Animations removed during the updateRemove-generated events could miss the frameEvents generated during the update (e.g. animation remove events) “fire within the same frame” (CL 8045604)

Implementation: CL 8045604 (merged 2026-07-14) moved document animation updates and scroll-animation servicing into the Step 11 position for all non-throttled documents, and dispatches each non-throttled controller’s animation events immediately after updating its animations — so events produced by the update are delivered in the same frame. Throttled (e.g. hidden) documents are not serviced on this cadence, as before.

Source: CL 8045604 commit message; CSS Transitions 2 §5.1 event dispatch; Web Animations — update animations and send events

behavior contract 2: media-query change before animation events

CSSOM View’s algorithm: for each MediaQueryList whose document is being rendered, “in the order they were created, oldest first”, if the list’s matches state changed since the last run, “fire an event named change at target using MediaQueryListEvent, with its isTrusted attribute initialized to true, its media attribute initialized to target’s media, and its matches attribute initialized to target’s matches state.”

SituationBefore Chrome 153 (Blink)From Chrome 153 (spec-aligned)
Viewport/class change flips a media query during iteration Nchange dispatched intermixed with animation events at the animation-events stepchange dispatched at the earlier media-query step, before pending animation events
change listener starts/cancels an animationResulting animation events raced in the same mixed batchListener runs first; animation events it causes are still collected and dispatched in the same iteration’s animation step
Legacy mql.addListener(cb) callbacksSeparate dispatch path from standard change eventsBoth paths observe the media-query step; page_animator.cc calls CallMediaQueryListListeners() before dispatching queued MediaQueryListEvent listeners when the flag is enabled. This is Blink source order, not a cross-engine ordering promise
Source: CL 8044688 commit message; CSSOM View — evaluate media queries and report changes

behavior contract 3: the compat flush after animation events

Blink historically used the animation-events step as an unfiltered flush for queued events beyond animation events. CL 8044688 splits this in two, in its own words:

“While HTML spec for Step 11 is only about animation updates, Blink has been dispatching all events without any filtering here. … We are splitting this dispatch in two: first dispatch the animation events as per Step 11, then dispatch all events not covered to maintain backward compatibility. We are avoiding unfiltered dispatch in the last step to prevent premature dispatch of any events covered by the previous steps in case any such event is queued after their dispatch before in the same loop.”

The M153 page_animator.cc predicate defines this flush by exclusion, not by a finite allowlist: it excludes scroll, scrollsnapchange, scrollsnapchanging, scrollend, resize, pagereveal, and events whose interface is MediaQueryListEvent. Remaining queued events, including animation events and the source-comment examples of <dialog> close and text-control select/change, are dispatched here. This is an implementation filter, not an exhaustive author-facing event list or a new timing guarantee for every unlisted event.

Source: CL 8044688 commit message (quoted verbatim); M153 Step 11 filter in page_animator.cc.

observing the new order (examples)

Nothing new to feature-detect, but the order can be measured. This probe was run in local headless Chrome 154.0.8037.97 (2026-10-08), with a CDP viewport override from 800 to 500 CSS pixels immediately after the opacity change. Run it on a page initially wider than 600px; let #timing-probe render before changing its opacity. CDP’s Emulation.setDeviceMetricsOverride (width 500, height 800, deviceScaleFactor 1, mobile false) supplies the resize — window.resizeTo() did not resize this headless build.

<div id="timing-probe" style="width:40px;height:40px;opacity:1;transition:opacity 1s"></div>
<script>
const trace = [];
let frame = 0;
function tick() { frame++; requestAnimationFrame(tick); }
requestAnimationFrame(tick);
const mql = matchMedia('(max-width:600px)');
mql.addEventListener('change', () => trace.push(['mq-change', frame]));
const box = document.querySelector('#timing-probe');
box.addEventListener('transitionrun', () => trace.push(['transitionrun', frame]));
// After two rAFs allow initial opacity to render, then run these two CDP steps:
box.style.opacity = '0';
trace.push(['set', frame]);
// CDP: Emulation.setDeviceMetricsOverride({width:500,height:800,
//   deviceScaleFactor:1,mobile:false}); then inspect trace after 1 second.
</script>

Observed flag comparison: with --enable-blink-features=EventTimingMatchingHTML, set, mq-change, and transitionrun were all recorded in frame 17, in that order. With --disable-blink-features=EventTimingMatchingHTML, set and mq-change were in frame 22, while transitionrun arrived in frame 23. The absolute frame numbers are incidental; the on/off difference reproduces the frame-late transition regression only with the flag disabled in this Chrome 154 probe (the flag-on run dispatched all three entries in one frame), and shows the media-query-before-transition ordering for this probe, not a universal assertion about every viewport/transition combination or an M153 binary.

The Chrome Platform Showcase feature route returned HTTP 200 (2026-10-08), but its runtime conformance is UNVERIFIED: both the frames-to-run and event-order concepts reported transitionrun one frame late in local Chrome 154.0.8037.97, even with --enable-blink-features=EventTimingMatchingHTML. The separate gendn flag comparison above resized the top-level CDP viewport from 800 to 500 CSS pixels immediately after changing opacity and saw all three entries in one frame with the flag on (the event a frame later with it off). The CPS concepts use their own embedded stage and breakpoint triggers. These different measurements do not establish a universal contradiction or prove the CPS example conforms: no live iframe is embedded until the setups are reconciled.

Source: ordering asserted by the ChromeStatus summary and CL 8044688; snippets are gendn-derived illustrations

web platform tests

The timing change rides on existing WPT suites — neither implementation CL adds new WPT files (their file lists touch only page_animator.cc, the runtime-flag record, and Chromium unit tests — verified in the CL file lists, 2026-07-29):

The ChromeStatus record links a sibling event-loop alignment test — new-scroll-event-dispatched-at-next-updating-rendering-time.html (scroll events at the scroll step) — viewed with the interop filter; it documents the same rendering-steps program rather than these two events directly.

Source: CL file lists (8044688, 8045604); WPT repository fetched 2026-07-29

browser compatibility

Interim tables. BCD records support for the events but not for dispatch timing (no BCD key exists for the alignment behavior; a webstatus.dev query returns zero matches, 2026-07-29). The alignment rows below come from the authoritative milestone listing, not BCD.

The alignment change (not from BCD)
EngineAligned timingEvidence
Chrome / Edge (Chromium)153 per listing; verify build behaviormilestone=153 listing; trunk stable versus M153 branch experimental; local Chrome 154 flag-on/off timing observation below
Firefox (Gecko)Already conformant (per listing)ChromeStatus record: the change makes Blink “interoperable with Gecko and WebKit”; vendor-position field records no objection (no notes)
Safari (WebKit)Already conformant (per listing)Same record; no WebKit standards-position link on record
The events themselves (BCD)
EventChromeFirefoxSafari
transitionrun (api.Element.transitionrun_event)745313.1
Media-query change (api.MediaQueryList.change_event)395514
Source: BCD api/Element.json; BCD api/MediaQueryList.json (both fetched 2026-07-29)

security and privacy

Source: CSSOM View algorithm; Web Animations algorithm; CL 8044688

specifications

DocumentRelevance
HTML Standard — event loop processing modelThe normative rendering-steps order (media-query evaluation before animation events); the listing’s “Step 3.10/3.11” refers to these sub-steps
CSSOM View — evaluate media queries and report changesThe change-event dispatch algorithm (oldest-first, on matches state change, MediaQueryListEvent payload)
Web Animations — update animations and send eventsThe animation-update-then-dispatch algorithm run at the animation-events step
CSS Transitions Level 2 §5.1 — event dispatchThe transition phase machine and the transitionrun mapping (idle → pending-or-before; target = owning element)
Source: specifications fetched 2026-07-29; maturity per the ChromeStatus record: “Final published standard”

see also