← 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.

Flag state. The milestone=153 listing files this feature under “Enabled by default” (verified 2026-07-29; the listing is authoritative for identity). The Blink runtime feature that gates the change is EventTimingMatchingHTML, recorded with status experimental in runtime_enabled_features.json5 at trunk (fetched 2026-07-29) and not marked public: true — so there is no chrome://flags entry. For local testing of the aligned behavior outside the rollout, launch Chrome with --enable-blink-features=EventTimingMatchingHTML. The two implementation CLs (8044688, 8045604) both landed behind this flag.

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 (status experimental, not public) in runtime_enabled_features.json5
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 eventsStandard MediaQueryListEvent “dispatched immediately in Step 10 alongside legacy mql.addListener() callbacks” (CL 8044688) — both paths observe the same step
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.”

Net effect for authors: events that belong to the named rendering steps (resize, scroll, media-query, animation) are no longer at risk of being flushed early by the catch-all in page_animator.cc; events the spec doesn’t assign to a step keep their historical delivery point. This is the piece that keeps the alignment web-compatible — the CL frames the second dispatch explicitly as backward compatibility, not a new contract.

Source: CL 8044688 commit message (quoted verbatim)

observing the new order (examples)

Nothing to feature-detect — the events and interfaces are unchanged — but the ordering is observable. These gendn-derived snippets (not from a spec; labelled as such) log the relative order so you can compare engines or pre/post-153 Chrome:

// Order probe: media-query change vs animation events in one iteration
const log = [];
const mql = matchMedia("(max-width: 600px)");
mql.addEventListener("change", () => log.push("mq-change"));

document.documentElement.style.transition = "margin-left 100s";
document.documentElement.addEventListener("transitionrun",
  () => log.push("transitionrun"), { once: true });

// Force both in one iteration: shrink the viewport and flip the property.
// Spec order (Chrome 153+): "mq-change" before "transitionrun".
// Old Blink: the two could appear in either relative order.
// Same-iteration transitionrun: listener observes the transition
// in the frame it was created (Chrome 153+), not a frame later.
el.addEventListener("transitionrun", (e) => {
  // e.elapsedTime === 0 at interval start (negative delay = -delay)
  console.log("running:", e.propertyName, e.elapsedTime);
});
el.style.transition = "opacity 1s";
el.style.opacity = "0";  // creates + queues in one style change

The Chrome Platform Showcase has no demo route for this feature (route HEAD-checked 404, 2026-07-29), so no live iframe is embedded; the snippets above are the canonical probes.

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)From Chrome 153milestone=153 listing (“Enabled by default”); gated by EventTimingMatchingHTML (flag record)
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