fix: insert position-area mapping styles into each target's own root - #446
fix: insert position-area mapping styles into each target's own root#446jpzwarte wants to merge 4 commits into
Conversation
`position-area` in a `:host` rule positions the shadow host, which lives in the outer tree, but the generated `--pa-value-*` mapping rule was inserted into the roots being polyfilled. A `<style>` in a shadow root never matches that root's own host, so the values stayed undefined and the host was left unpositioned. Record the style container of each target while the rules are generated, and insert the stylesheet into those containers instead. Targets inside a polyfilled shadow root resolve to the same container as before. Refs oddbird#444 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
✅ Deploy Preview for anchor-polyfill ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
✅ Deploy Preview for anchor-position-wpt canceled.
|
jamesnw
left a comment
There was a problem hiding this comment.
Just a brief look so far. I would love a reproduction I can play with, as it isn't clear to me that this should work. I know anchor references can't cross shadow boundaries, but once an element has a default anchor, can it use it across shadow boundaries? Does that also work if you use anchor() without specifying an anchor?
Also, is this limited to position-area because we don't need to write custom styles for anchor-size() or anchor()?
jamesnw
left a comment
There was a problem hiding this comment.
I think this works. I've done a bit of thinking on whether this matches the spec.
In particular- https://drafts.csswg.org/css-anchor-position/#target:~:text=Note%3A%20An,them%2E%29
Note: An anchor-name defined by styles in one shadow tree won’t be seen by anchor functions in styles in a different shadow tree, preserving encapsulation. However, elements in different shadow trees can still anchor to each other, so long as both the anchor-name and anchor function come from styles in the same tree, such as by using ::part() to style an element inside a shadow. (Implicit anchor elements also aren’t intrinsically limited to a single tree, but the details of that will depend on the API assigning them.)
So :host{ bottom: anchor(--position-area-on-host top) } or :host{ position-anchor: --position-area-on-host } do not work. The example here works because we are setting a default anchor element with the style tag, which is in the same tree as where the anchor is defined.
If that matches your understanding, I think this makes sense, and there's just a few small changes. Thanks!
| // the tree of every element its rules match, as recorded while the | ||
| // rules were generated. Those are not always the roots being | ||
| // polyfilled: a `position-area` in a `:host` rule targets the shadow | ||
| // host, which lives in the outer tree. Fall back to the roots when |
There was a problem hiding this comment.
Is this the behavior we want? If there are no containers recorded, do we still need to add styles for this?
| // within its own tree, and the elements these rules target do not always live | ||
| // in the roots being polyfilled — a `:host` rule styles the shadow host, | ||
| // which sits in the *outer* tree. | ||
| containers?: Set<ShadowRoot | HTMLHeadElement>; |
There was a problem hiding this comment.
I was curious about making this required. It seems like the only change would be that transformCSS currently is removing containers from the returned styleData. I don't think we use it after transformCSS, but I think I'd prefer to have containers required on StyleData, and persist it.
It does match my understanding: |


Fixes #444
position-areain a:hostrule positions the shadow host, which lives in the outer tree, but the generated--pa-value-*mapping rule was inserted into the roots being polyfilled. A<style>in a shadow root never matches that root's own host, so the values stayed undefined and the host was left unpositioned.Record the style container of each target while the rules are generated, and insert the stylesheet into those containers instead. Targets inside a polyfilled shadow root resolve to the same container as before.