You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[css-anchor-position-1] position-visibility: anchors-visible should be clear about when is visibility determined #12732
Is the box's visibility property really intended to compute toforce-hidden? There's no test for this, and I think it would make more sense to be a used-value time thing. In fact, at least that's how WebKit implements it (and Blink probably, too, given there's no test for force-hidden at all in all of WPT). Computes to would imply that you need to update the style in the whole subtree, because visibility is inherited, which seems rather unfortunate. It also has bigger ramifications (affects style container queries and so on...).
There's nothing that says when the visibility is checked. I'm assume, given the definition, the idea is that you check it every layout? If so I think that makes an even stronger case for it being used-value time tbh...
I guess the idea is that #10182 allowed you to trigger enter / exit transitions (not clear to me how... I guess transitioning position-visibility + container-queries or something)?
Maybe a more sensible approach is to use the same timing we use to evaluate fallbacks (ResizeObserver timing)?
If we don't want to change the timing here (which btw I think would allow for more interesting behavior, such as proper IntersectionObserver-like visibility testing), I think at least a note in the spec about it being evaluated every layout would be nice, since it came as a surprise to me (when I first read about this feature, I assumed it would use the existing ResizeObserver-timed mechanics).
Oh! Interesting. I think that's the sensible thing to do... But that looks nothing like what the spec says, since then presumably it also supports things like clip-path etc, and all the scrollers all the way to the root, right? (apart from the timing difference being observable of course)
@tabatkins I see you landed a spec edit for this. Was that intentional? if so it should probably use the concepts from whatwg/html#11613? I assume Blink uses the same mechanism and not something weirder?
The CSS Working Group just discussed [css-anchor-position-1] position-visibility: anchors-visible should be clear about when is visibility determined.
The full IRC log of that discussion
<TabAtkins> emilio: the spec doesn't say when the anchor's visibility is checked
<TabAtkins> emilio: and when I was looking to implement, I realized the spec technically allows....
<TabAtkins> emilio: if it did something more complicated you could only do it as post layout
<TabAtkins> emilio: but the clipping thing specified is at layout time
<TabAtkins> emilio: the issue is about defining *when*
<TabAtkins> emilio: webkit does it during layout. blink does some intersection observer thing, which is a bit more flexible
<TabAtkins> emilio: but might be more confusing
<TabAtkins> emilio: if you change layout in a way that overflows, then elementFromPoint(), whether that hit test succeeds or not depends on timing
<TabAtkins> emilio: no strong opinion on what happens, just want it specified
<TabAtkins> emilio: I think Tab added an edit
<TabAtkins> emilio: should check with WebKit. and spec edit should use some of the post-layout things Rune is doing.
<futhark> q+
<TabAtkins> TabAtkins: I specified "just before ResizeObserver", because that's what Philip said and Emilio agreed. More details would be great.
<TabAtkins> emilio: it needs to be a bit more detailed, because ResizeObserver loop is more stuff - content-visibility, scroll size observer... it needs to be specced in amore detailed way. rune can give details
<astearns> ack futhark
<TabAtkins> futhark: sorry, don't have specific context on position-visibliity, but it does make sense to happen at same time
<TabAtkins> futhark: also on whether rpost-layout snapshot happens before or after resizeobserver
<TabAtkins> futhark: ties in, I agree
<TabAtkins> fantasai: I pinged antii to see if he has feedback. I have no idea how this timing fits in with anything
<fantasai> s/antii/antti/
<TabAtkins> fantasai: I just want authors to have something that generally works. not sure to what extent we care about exact nuances beyond that
<emilio> q+
<TabAtkins> fantasai: so how much of this is about authors caring about timing, and how much is about writing WPTs
<TabAtkins> fantasai: so long as the author-observable behavior is something they're happy about, and we have interop on aspects that we need *for authors*
<astearns> ack emilio
<TabAtkins> emilio: not about locking things down. timing issue ends up... if we dont' define it, we'll hit compat issues.
<TabAtkins> emilio: it's pretty different observable behavior. if you do it before resize, then layout changes from an RO won't hide an anchor until next frame
<TabAtkins> emilio: on flip side, if you do it during layout, that's most CSS-y it's not really observable, but it's less flexible. can't check for intersection with other elements.
<TabAtkins> emilio: i'm assuming blink is actually reusing Intersection observer, which does a lot more than just checking scroll overflow
<TabAtkins> emilio: that's a big behavior different, should use one or the other
<TabAtkins> emilio: IO uses overflow-clip, o-c-margin, etc
<TabAtkins> emilio: and those are probably something the author would expect to work
<TabAtkins> fantasai: yeah, defining whether we check clip is definitely defined
<TabAtkins> TabAtkins: I think that's already defined
<fantasai> TabAtkins: We should define behavior we want
<TabAtkins> emilio: right now I think spec is just overflow based
<TabAtkins> astearns: so how to resolve on this?
<TabAtkins> emilio: if we want to check IO things, we need to define a fixed point in the frame timing
<TabAtkins> fantasai: I think we should just be checking for what's in the spec right now
<TabAtkins> fantasai: if we did clip path and other stuff.... I don't think tha't snecessarily what authors would expect
<TabAtkins> emilio: if you did this as an author you'd do IO
<TabAtkins> fantasai: sure but i'm not convinced it's really what you *want*
<TabAtkins> fantasai: so we have some qs to investigate. what do we think authors expect about clip behavior and anchor visibility? and the timing question
<TabAtkins> fantasai: which depends on that first q
<TabAtkins> emilio: I think that makes sense
<fantasai> s/first q/first question, so let's answer that one first/
<TabAtkins> emilio: I think spec currently only does check from the anchor to the CB of the positioned El, and that's another big change from IO
<TabAtkins> fantasai: right, I think IO isn't what we want to do
<TabAtkins> emilio: maybe. I think it's weird, for example, to not intersect with the viewport.
<TabAtkins> astearns: take back to the issue, then?
<TabAtkins> fantasai: yes
So the two questions that came out of the call were:
What types of clipping should position-visibility be checking for?
When should it be calculated? (This is somewhat dependent on the first question.)
For the first question, it would be useful to hear from anchorpos users. Currently the spec only checks for overflow clipping between the anchor and the abspos CB. It doesn't check for visibility in the viewport or clip-path or anything else. Personally I think this is the right answer.
For the second question, WebKit re-evaluates after each layout, which means that there's no lagging across frames. We think this is better behavior for users, and would prefer if it were allowed by the spec.
TL;DR: I propose that we resolve no change to the existing WD spec, which already specifies overflow clips up to the abspos CB, and also the timing of visibility checks. I think this already agrees with implementation behavior for both Chrome and Safari.
What types of clipping should position-visibility be checking for?
I agree that overflow clips between the anchor element and the abspos CB should be taken into account, but not the viewport. The reason is that, if the anchored element looks to the user like it's part of a subscroller, then it doesn't make sense to the user what it's anchoring to if that anchor point is not even visible on the screen.
Example here (observe what happens when you scroll further up or down in that scroller which has a tooltip for "Item 6"). (Note: this demo is from @una who is close to the developer community.)
The browser viewport doesn't have this problem because its clip always applies to everything--including anchored elements--and so there is no point to doing it there because it will have no effect. But for a subscroller, the anchored element escapes the clip of the subscroller because it's out of flow.
I also don't think other clips need to be taken into account, because it's just a scrolling effect due to the user agent controlling scrolling, not any other visual effect.
When should it be calculated?
I agree that visibility should be re-evaluated after every layout (*) so that there is no lagging across frames.
From what @fantasai said, I think the WebKit and Blink implementations actually already match.
Blink does position-visibility hiding computation updates after layout and before JS ResizeObservers (but it is also part of the loop between them, so if a ResizeObserver dirties layout then visibility will be re-calculated after the subsequent layout).
Implementation note: The intersection observation generated for position-visibility by Blink is also delivered during that same frame. We do this with a special kind of Blink-internal sync observation not available to JS-generated IntersectionObservers.
(*) Or more more precisely, every layout that is part of the update-the-rendering/animation frame generation steps.
I think this already agrees with implementation behavior for both Chrome and Safari.
It doesn't? Safari does it during the style / layout loop afaict.
Also, Blink afaict just has the behavior of IntersectionObserver with root: <the closest ancestor to the containing-block>. Let me know if I'm misreading the code.
But that's not what the spec says to do (that accounts for a lot more than scrolling overflow, like overflow: clip, clip-path, etc).
Whether or not anchor is clipped by intervening boxes must be checked after updating content relevancy for a document (see content-visibility in [css-contain-2]) and before running any IntersectionObserver, and may also be checked at other times to improve responsiveness.
@emilio@andruud@anttijk Can you verify whether this matches your expectations on what this is supposed to say? Tab and I aren't very clear on how all the timing details stack.
I think the right fix would be to expose an algorithm or hook to check the intervening boxes and call it somewhere from steps 16/17 of https://html.spec.whatwg.org/#update-the-rendering. The version of anchors-visible that browsers implement can probably run once after the loop (so would become step 17), but for the version that actually changes the computed value of visibility that's trickier.
Whether or not anchor is clipped by intervening boxes must be checked after updating content relevancy for a document (see content-visibility in [css-contain-2]) and running any ResizeObserver, but before running any IntersectionObserver. It may also be checked at other times to improve responsiveness.
Activity
emilio commentedon Sep 4, 2025
cc @anttijk
emilio commentedon Sep 4, 2025
If we don't want to change the timing here (which btw I think would allow for more interesting behavior, such as proper IntersectionObserver-like visibility testing), I think at least a note in the spec about it being evaluated every layout would be nice, since it came as a surprise to me (when I first read about this feature, I assumed it would use the existing ResizeObserver-timed mechanics).
progers commentedon Sep 4, 2025
For what it's worth, Chromium's implementation uses our intersection observer code and runs it just prior to resize observer.
emilio commentedon Sep 4, 2025
Oh! Interesting. I think that's the sensible thing to do... But that looks nothing like what the spec says, since then presumably it also supports things like
clip-pathetc, and all the scrollers all the way to the root, right? (apart from the timing difference being observable of course)[css-anchor-position] Specify the timing of 'clipped by intervening b…
emilio commentedon Sep 24, 2025
@tabatkins I see you landed a spec edit for this. Was that intentional? if so it should probably use the concepts from whatwg/html#11613? I assume Blink uses the same mechanism and not something weirder?
css-meeting-bot commentedon Sep 24, 2025
The CSS Working Group just discussed
[css-anchor-position-1] position-visibility: anchors-visible should be clear about when is visibility determined.The full IRC log of that discussion
<TabAtkins> emilio: the spec doesn't say when the anchor's visibility is checked<TabAtkins> emilio: and when I was looking to implement, I realized the spec technically allows....
<TabAtkins> emilio: if it did something more complicated you could only do it as post layout
<TabAtkins> emilio: but the clipping thing specified is at layout time
<TabAtkins> emilio: the issue is about defining *when*
<TabAtkins> emilio: webkit does it during layout. blink does some intersection observer thing, which is a bit more flexible
<TabAtkins> emilio: but might be more confusing
<TabAtkins> emilio: if you change layout in a way that overflows, then elementFromPoint(), whether that hit test succeeds or not depends on timing
<TabAtkins> emilio: no strong opinion on what happens, just want it specified
<TabAtkins> emilio: I think Tab added an edit
<TabAtkins> emilio: should check with WebKit. and spec edit should use some of the post-layout things Rune is doing.
<futhark> q+
<TabAtkins> TabAtkins: I specified "just before ResizeObserver", because that's what Philip said and Emilio agreed. More details would be great.
<TabAtkins> emilio: it needs to be a bit more detailed, because ResizeObserver loop is more stuff - content-visibility, scroll size observer... it needs to be specced in amore detailed way. rune can give details
<astearns> ack futhark
<TabAtkins> futhark: sorry, don't have specific context on position-visibliity, but it does make sense to happen at same time
<TabAtkins> futhark: also on whether rpost-layout snapshot happens before or after resizeobserver
<TabAtkins> futhark: ties in, I agree
<TabAtkins> fantasai: I pinged antii to see if he has feedback. I have no idea how this timing fits in with anything
<fantasai> s/antii/antti/
<TabAtkins> fantasai: I just want authors to have something that generally works. not sure to what extent we care about exact nuances beyond that
<emilio> q+
<TabAtkins> fantasai: so how much of this is about authors caring about timing, and how much is about writing WPTs
<TabAtkins> fantasai: so long as the author-observable behavior is something they're happy about, and we have interop on aspects that we need *for authors*
<astearns> ack emilio
<TabAtkins> emilio: not about locking things down. timing issue ends up... if we dont' define it, we'll hit compat issues.
<TabAtkins> emilio: it's pretty different observable behavior. if you do it before resize, then layout changes from an RO won't hide an anchor until next frame
<TabAtkins> emilio: on flip side, if you do it during layout, that's most CSS-y it's not really observable, but it's less flexible. can't check for intersection with other elements.
<TabAtkins> emilio: i'm assuming blink is actually reusing Intersection observer, which does a lot more than just checking scroll overflow
<TabAtkins> emilio: that's a big behavior different, should use one or the other
<TabAtkins> emilio: IO uses overflow-clip, o-c-margin, etc
<TabAtkins> emilio: and those are probably something the author would expect to work
<TabAtkins> fantasai: yeah, defining whether we check clip is definitely defined
<TabAtkins> TabAtkins: I think that's already defined
<fantasai> TabAtkins: We should define behavior we want
<TabAtkins> emilio: right now I think spec is just overflow based
<TabAtkins> astearns: so how to resolve on this?
<TabAtkins> emilio: if we want to check IO things, we need to define a fixed point in the frame timing
<TabAtkins> fantasai: I think we should just be checking for what's in the spec right now
<TabAtkins> fantasai: if we did clip path and other stuff.... I don't think tha't snecessarily what authors would expect
<TabAtkins> emilio: if you did this as an author you'd do IO
<TabAtkins> fantasai: sure but i'm not convinced it's really what you *want*
<TabAtkins> fantasai: so we have some qs to investigate. what do we think authors expect about clip behavior and anchor visibility? and the timing question
<TabAtkins> fantasai: which depends on that first q
<TabAtkins> emilio: I think that makes sense
<fantasai> s/first q/first question, so let's answer that one first/
<TabAtkins> emilio: I think spec currently only does check from the anchor to the CB of the positioned El, and that's another big change from IO
<TabAtkins> fantasai: right, I think IO isn't what we want to do
<TabAtkins> emilio: maybe. I think it's weird, for example, to not intersect with the viewport.
<TabAtkins> astearns: take back to the issue, then?
<TabAtkins> fantasai: yes
fantasai commentedon Sep 24, 2025
So the two questions that came out of the call were:
position-visibilitybe checking for?For the first question, it would be useful to hear from anchorpos users. Currently the spec only checks for
overflowclipping between the anchor and the abspos CB. It doesn't check for visibility in the viewport orclip-pathor anything else. Personally I think this is the right answer.For the second question, WebKit re-evaluates after each layout, which means that there's no lagging across frames. We think this is better behavior for users, and would prefer if it were allowed by the spec.
chrishtr commentedon Sep 29, 2025
TL;DR: I propose that we resolve no change to the existing WD spec, which already specifies overflow clips up to the abspos CB, and also the timing of visibility checks. I think this already agrees with implementation behavior for both Chrome and Safari.
I agree that overflow clips between the anchor element and the abspos CB should be taken into account, but not the viewport. The reason is that, if the anchored element looks to the user like it's part of a subscroller, then it doesn't make sense to the user what it's anchoring to if that anchor point is not even visible on the screen.
Example here (observe what happens when you scroll further up or down in that scroller which has a tooltip for "Item 6"). (Note: this demo is from @una who is close to the developer community.)
The browser viewport doesn't have this problem because its clip always applies to everything--including anchored elements--and so there is no point to doing it there because it will have no effect. But for a subscroller, the anchored element escapes the clip of the subscroller because it's out of flow.
I also don't think other clips need to be taken into account, because it's just a scrolling effect due to the user agent controlling scrolling, not any other visual effect.
I agree that visibility should be re-evaluated after every layout (*) so that there is no lagging across frames.
From what @fantasai said, I think the WebKit and Blink implementations actually already match.
Blink does position-visibility hiding computation updates after layout and before JS ResizeObservers (but it is also part of the loop between them, so if a ResizeObserver dirties layout then visibility will be re-calculated after the subsequent layout).
Implementation note: The intersection observation generated for
position-visibilityby Blink is also delivered during that same frame. We do this with a special kind of Blink-internal sync observation not available to JS-generated IntersectionObservers.(*) Or more more precisely, every layout that is part of the update-the-rendering/animation frame generation steps.
chrishtr commentedon Sep 29, 2025
I'd like to discuss this and hopefully resolve as a high priority item this week, since it affects Interop 2025.
emilio commentedon Sep 29, 2025
It doesn't? Safari does it during the style / layout loop afaict.
Also, Blink afaict just has the behavior of
IntersectionObserverwithroot: <the closest ancestor to the containing-block>. Let me know if I'm misreading the code.But that's not what the spec says to do (that accounts for a lot more than scrolling overflow, like
overflow: clip,clip-path, etc).28 remaining items
[css-anchor-position-1] Add clip-path to anchors-visible check and ti…
[css-anchor-position-1] Clarify timing of anchors-visible checks. #12732
fantasai commentedon Nov 5, 2025
Ok, we committed the following text:
@emilio @andruud @anttijk Can you verify whether this matches your expectations on what this is supposed to say? Tab and I aren't very clear on how all the timing details stack.
emilio commentedon Nov 5, 2025
I think the right fix would be to expose an algorithm or hook to check the intervening boxes and call it somewhere from steps 16/17 of https://html.spec.whatwg.org/#update-the-rendering. The version of anchors-visible that browsers implement can probably run once after the loop (so would become step 17), but for the version that actually changes the computed value of
visibilitythat's trickier.emilio commentedon Nov 5, 2025
If we decide to go for tweaking styles or what not, reusing the same steps whatwg/html#11613 is introducing probably makes more sense.
emilio commentedon Nov 5, 2025
cc @lilles for the above :)
[css-anchor-position-1] Clarify anchors-visible is after ResizeObserv…
fantasai commentedon Nov 5, 2025
Ok, updated to the following for now:
Lmk if this is good enough.