NEW301461
[css-transitions][css-anchor-position] transitioning an accelerated property to show a popover with anchor positioning yields two transitions, fails to transition again
https://bugs.webkit.org/show_bug.cgi?id=301461
Summary [css-transitions][css-anchor-position] transitioning an accelerated property ...
Antoine Quint
Reported 2025-10-25 05:44:08 PDT
Created attachment 477196 [details] Testcase This is a bug for one of the issues shown in bug 301070, or perhaps it'll be a duplicate, but there's something fishy going on when using a CSS Transition to show a popover when anchor positioning is involved. The attached test case does the following: ====================== <style> [popover] { transition: opacity 1s ease-in-out; position-try: flip-inline; &:popover-open { display: block; opacity: 1; } @starting-style { &:popover-open { opacity: 0; } } } </style> <button type="button" popovertarget="popover">Show popover</button> <div id="popover" popover> <p>Popover</p> </div> ====================== Clicking the "Show popover" visually has the right behavior but as it turns out the `opacity` transitions run twice, a second transition starting once the first, expected, transition completes. Another issue is that after dismissing the popover, the transition will not run again.
Attachments
Testcase (965 bytes, text/html)
2025-10-25 05:44 PDT, Antoine Quint
no flags
Testcase (1.04 KB, text/html)
2025-10-25 11:10 PDT, Antoine Quint
no flags
Antoine Quint
Comment 1 2025-10-25 05:45:24 PDT
Using another accelerated property, such as `translate`, reproduces the issue. Using a non-accelerated property, such as `margin-left`, does not reproduce the issue.
Antoine Quint
Comment 2 2025-10-25 10:39:14 PDT
The reason it does not look like a second transition is running is because it's transitioning from `0.999571919` to `1`. I'm not sure yet why it's picking `0.999571919`, which is clearly an animated value and which should not be considered as a value for considering a transition, over the underlying value, which should be 1.
Antoine Quint
Comment 3 2025-10-25 10:52:48 PDT
We get `oldStyle` in `Style::TreeResolver::createAnimatedElementUpdate()` by calling `resolveStartingStyle()` when the first transition is created. When the second is created, we get it by calling `beforeResolutionStyle()`. Somehow an animated value snuck into what is stored in `m_savedBeforeResolutionStylesForInterleaving`.
Antoine Quint
Comment 4 2025-10-25 11:02:17 PDT
I see that there's some code where `m_savedBeforeResolutionStylesForInterleaving` is populated which is specific to when anchor positioning is involved in `Style::: // Ensure that style resolution visits any unresolved anchor-positioned elements. if (elementAndState.value->stage < AnchorPositionResolutionStage::Resolved) { const_cast<Element&>(*elementAndState.key.first).invalidateForResumingAnchorPositionedElementResolution(); m_needsInterleavedLayout = true; saveBeforeResolutionStyleForInterleaving(*elementAndState.key.first); } I get a hunch that is something is wrong either in what we store in `m_savedBeforeResolutionStylesForInterleaving` or the circumstance under which we use it.
Antoine Quint
Comment 5 2025-10-25 11:09:41 PDT
Yes, logging indicates the `oldStyle` we get for the second transition is read from `m_savedBeforeResolutionStylesForInterleaving` and was stored in the function call above. Somehow we're resolving an animated style there, which is incorrect.
Antoine Quint
Comment 6 2025-10-25 11:10:08 PDT
Created attachment 477199 [details] Testcase
Radar WebKit Bug Importer
Comment 7 2025-10-27 14:17:16 PDT
Note You need to log in before you can comment on or make changes to this bug.