[csswg-drafts] [cssom-view] Pass scrollX/scrollY in scrollend event (#13505)

kurtextrem has just created a new issue for https://github.com/w3c/csswg-drafts:

== [cssom-view] Pass scrollX/scrollY in scrollend event ==
The `scrollend` event sees more and more use, because it's more efficient to use when responding to a scroll motion in some way (e.g. to understand where a user landed when the scroll motion has finished). However, when you know a scroll motion has ended, you very likely (I'd say in 99% of cases) want to know where exactly the user now is. This means you need to do this:

```
function onScrollEnd(event) {
  ...
  const scrollY = window.scrollY
  const scrollX = window.scrollX
  ...
}

window.addEventListener("scrollend", onScrollEnd)
```

Which can be bad for performance again, as reading those props can cause a [reflow](https://gist.github.com/paulirish/5d52fb081b3570c81e3a) if something has changed style/layout meanwhile (which can certainly be the cause while scrolling through something / stopping somewhere). 

**Idea**: If we pass the `scrollY`/`scrollX` as part of the `event` object, developers could read the scroll position 'for free' (without the potential of a reflow), thus maximizing the performance aspect of this event (over `scroll`). Working with those newly added props would also be easy for devs (e.g. `event.scrollX ?? window.scrollX`).

---

I've considered alternatives that userland can implement today, but they come with quite a lot more code:

<details>
<summary>ScrollTimeline API + scrollend</summary>
  
```js
const scroller = document.scrollingElement; // root document scroller

// Timelines (one per axis)
const yTimeline = new ScrollTimeline({ source: scroller, axis: "block" });
const xTimeline = new ScrollTimeline({ source: scroller, axis: "inline" });

// Cache the scroll ranges (do NOT compute these inside scrollend)
let maxY = 1, maxX = 1;
function recalcRanges() {
  maxY = Math.max(1, scroller.scrollHeight - scroller.clientHeight);
  maxX = Math.max(1, scroller.scrollWidth  - scroller.clientWidth);
}
recalcRanges();

new ResizeObserver(recalcRanges).observe(scroller);
window.addEventListener("resize", recalcRanges);

// Utility: timeline -> 0..1
function progress01(tl) {
  const t = tl.currentTime;
  const d = tl.duration;
  if (t == null || !d) return null;
  const p = Number(t) / Number(d);
  return Math.min(1, Math.max(0, p));
}

addEventListener("scrollend", () => {
  const py = progress01(yTimeline);
  const px = progress01(xTimeline);

  const scrollY = py == null ? null : py * maxY;
  const scrollX = px == null ? null : px * maxX;

  console.log("scrollend ->", stored);
})
```
  
</details>

Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/13505 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Tuesday, 17 February 2026 09:17:18 UTC