overflow-anchor is not needed to reproduce, but proves that the difference is not in anchor selection, that is, it just forces
#content to be selected as the anchor).
So, I think this is all working per spec. The anchor should be
<div id="#content"> (I've just made the otehr nodes
overflow-anchor: none to ensure that the anchor isn't selected elsewhere, even though it shouldn't).
The website is moving the anchor up by shrinking the height of
#fakeHeader, and thus the engine is expected to correct that offset by scrolling back to the top and firing an scroll event (which would in turn expand the header and do the opposite, causing the flickering observed here).
https://drafts.csswg.org/css-scroll-anchoring/#suppression-triggers doesn't mention
overflow at all, and mentions suppressing adjustments only if the computed
height property changes in the scroll anchor or one of its ancestors. The page keeps a fixed header and an in-flow
#fakeHeader of the same height, so there's no
position change or other such property. So tldr none of those clauses apply and we should apply the adjustments.
Now, there are multiple things that make the test-case not reproduce the issue:
If you don't change
overflow (which in Gecko reframes and thus causes a harder relayout than just changing
height) you would hit our version of this chromium bug.
That is, we queue scroll anchor adjustment requests when the scroll frame is reflowed, or when a node in the anchor chain is reflowed and is the root of the reflow.
So without the
overflow change we'll miss it and not request an adjustment at all (which to be clear is wrong). My guess is that this is why the website works in Chromium.
Various timing differences
If you use something else than
setTimeout(.., 0), the bug goes away immediately.
If you don't delay the thing, then the heuristic described here comes into play and works, great!
If you delay it enough such as that you've processed another scroll event, then the bug doesn't reproduce, because on that second scroll event you schedule an update that overrides the first, and afterwards the next scroll event is also consistent so you get into a stable state without flickering.
So the only meaningful behavior differences between browsers are:
And thus, I have no idea how to go about fixing this, so far, other than tracking the timeout as "coming from the scroll event", maybe, and treating it the same.
In terms of the page's author, they could just remove the setTimeout, I'd think, or set
overflow-anchor: none on the document element.