Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-properties-values-api] Should property registration be scoped? #939

smfr opened this issue Aug 23, 2019 · 3 comments


Copy link

commented Aug 23, 2019

The fact that property registration is document global makes it impossible to use a custom property privately in a shadow tree. Maybe registration should be scoped somehow, optimally to a style sheet or shadow scope.


This comment has been minimized.

Copy link

commented Sep 13, 2019

Like other features that would benefit from scoping (@keyframes, @font-face, ...) it's not clear how they should behave when the scopes interact. I don't have any bright ideas yet, but a few questions off the top of my head:

If limited to a shadow scope:

  • What happens when the property inherits from one scope into another, and the registration details change between scopes?
  • What does it mean to use constructable style sheets, where the one CSSStyleSheet object could be inserted into multiple shadow trees, and the registration differs between shadow trees?

If limited to a style sheet:

  • Does this mean that you can't use that custom property in style="" attributes?
  • What if there are two style sheets that use different registrations, but whose rules apply to the same element?

This comment has been minimized.

Copy link

commented Sep 16, 2019

I strongly agree that it would be great to scope these, in the same way as we intend to scope other CSS values. (And on that point, will someone please either commit to this proposal or offer a credible alternative?)

This means scoping to tree scopes, and the registration you use depends on the scope the stylesheet is in. (Tho this has some issues, which I'll discuss in a sec.)

What happens when the property inherits from one scope into another, and the registration details change between scopes?

I think inheritance should happen with the synthesized token stream, as if you'd just set that token stream directly in the new context. Syntax has only a relatively small effect on registered properties, just making it go iacvt if necessary, and affecting how it reifies in Typed OM.

What does it mean to use constructable style sheets, where the one CSSStyleSheet object could be inserted into multiple shadow trees, and the registration differs between shadow trees?

You already have to track the stylesheet separately in each location it's inserted into, as the separate locations can already clash and have to be resolved based on document order/shadow origin/etc. (Eg a stylesheet can be inserted into both the outer page and a shadow, targeting the same element with a .foo rule from the light side and a :host rule from the shadow side.)

I think the biggest conflict here is: what registration does an element use when it's a shadow host? That is, if the main page registers --foo with syntax:"<length>", and the shadow registers it with syntax:"<color>", if you set "--foo: red;" on a shadow host is it iacvt or a valid red?

Perhaps it matters based on where that rule comes from? Aka, a custom property's value carries the value's scope with it, and once you run the cascade and figure out which value wins, you know how to process it as a computed value? I think this matches with the proposed behavior in w3c/csswg-drafts#1995 for other properties -- setting font-family: foo can refer to either the light or shadow @font { font-family: foo; } based on whether the declaration is from the light or shadow tree.

However, it does mean that a script trying to use the Typed OM to interact with the property might be confused by what it gets! In my example, if the outer page asks for the value, it'll be expecting a CSSNumericValue, but it might instead get a CSSColorValue if the declaration from the shadow wins. Maybe that's okay?

An alternative is that the element uses the declaration of the tree it's in, always. This means that a shadow tree can't reliably register a property and then use that property on the :host element, because if the outer page has a conflicting registration, the property will become iacvt if the shadow rule wins the cascade. I guess we'd then document that shadows should never use custom properties on :host for any reason (whether you register the property or not!), and instead only use them on top-level elements actually in the shadow tree.

I don't think there's any completely ideal answer here.

@w3c w3c deleted a comment from css-meeting-bot Sep 20, 2019

This comment has been minimized.

Copy link

commented Sep 20, 2019

The Houdini Task Force just discussed Scoping property registrations in the shadows.

The full IRC log of that discussion <myles_> Topic: Scoping property registrations in the shadows
<TabAtkins> github:
<iank_> scribenick: iank_
<iank_> TabAtkins: Simon brought up, if we want prop registration scooped to shadow trees.
<iank_> TabAtkins: Best case an custom element will unregister a property, and reregister it.
<iank_> TabAtkins: There is a meta issue around things not being scoped in CSS.
<iank_> TabAtkins: 1) What happens when a property registered in the light dom, inherits into the shadow dom, and there is different property registrations.
<iank_> TabAtkins: I suspect that we can basically, it keeps around a synthesized property string, as it goes into the new thing, it can be reinterpreted.
<iank_> TabAtkins: This sounds similar if it wasn't registered.
<iank_> TabAtkins: If you do a size property, it'll probably be a <length> it both places.
<iank_> TabAtkins: You can code defensively, but resetting at the top of the shadow root.
<iank_> TabAtkins: If it crosses the boundary it just gets reinterpreted as a token stream.
<TabAtkins> s/but/by/
<iank_> heycam: A broader problem seems to be what .... there is no good way to partition these properties.
<iank_> heycam: If you have multiple registrations.
<iank_> TabAtkins: Nothing more specific.
<iank_> heycam: I could imagine 2 custom element authors, both coming up with a --theme property independently.
<iank_> heycam: No way to handle that these could be interpreted differently.
<iank_> TabAtkins: As long as the two components are siblings you could set it above the CEs.
<iank_> TabAtkins: If they are nested, the outer CE knows that it nested the child.
<iank_> iank_: Has CE scoping occured yet?
<iank_> masonfreed: Still not solved yet.
<iank_> heycam: If we expect component authors to use suitably named properties to avoid conflicts, then the solution you described sounds fine.
<iank_> heycam: 90% of CP usage I see, is setting the properties on the root.
<iank_> fremy: Another option would be to, have a map of token streams, and when you read it , it can switch based on the reading context.
<iank_> fremy: Its consistent within a property tree, downside if you have slots you can't reset these.
<iank_> fremy: We might want to ask people who are using CEs on how they use them.
<TabAtkins> problem case: Light-dom author sets a theming property expecting it to apply to whole page. Shadow-dom author uses colliding name in their shadow. Shadow version of the property is what the slotted content sees, not the light-author's intended light value.
<iank_> heycam: Can you describe other discussions?
<iank_> TabAtkins: Yes
<iank_> TabAtkins: discussion was about font-face but was about other things.
<iank_> TabAtkins: not just font-face, fill: url(#something), etc.
<iank_> TabAtkins: A lot of confusion.
<iank_> TabAtkins: People think that you just walk upwards, but this would be bad, as unreliably interpreted differently.
<iank_> TabAtkins: My idea - each value which has this context depedence, it keeps around a link to where it was declared. As its passed around contexts, it keeps a reference to what defined it.
<iank_> TabAtkins: The reference would be explicitly caught, and reflected in the TypedOM version.
<iank_> TabAtkins: It'll be Document, or ShadowTree, etc, could grab the value, and use it elsewhere.
<iank_> heycam: On font-face specifically not sure how this effects document.fonts
<iank_> TabAtkins: ShadowTree would have a tree.fonts, conceptually.
<iank_> TabAtkins: keyframes rules, etc would also be what was defined within your scope, but would still work if you interited a keyframe across a shadow root boundary.
<iank_> heycam: Does this match what fremy described?
<iank_> TabAtkins: Yes.
<iank_> TabAtkins: That would solve the problem which i minuted earlier. Keeping the simple keeping the value with a single reference. Complexity is a little worrying.
<iank_> smfr: Is any of this written down anywhere?
<iank_> TabAtkins: Only present within that issue thread. As nobody has said this is good.
<iank_> TabAtkins: <snark>
<iank_> smfr: I'll try and get our CSS folks to review it.
<iank_> emilio: I don't think @font-face works within a shadow tree.
<iank_> emilio: keyframes don't work, blink/ff do something different to webkit.
<iank_> TabAtkins: Yeah would like to get a consistent answer.
<emilio> s/don't work/don't work the same across browsers
<iank_> TabAtkins: What registration use when it is a Shadow Host. Light DOM sees it as a normal element, Shadow DOM sees it as a :root.
<iank_> TabAtkins: Which registration should it use?
<iank_> TabAtkins: Not sure.
<iank_> TabAtkins: 1) Uses the reg. of whereever that style came from, outer uses outer reg. for example.
<iank_> Good thing: styles always work, as long as they don't touch at the same time. But unpredictable for what TypedOM returns.
<iank_> fremy: But if you do what I said it can support both.
<iank_> TabAtkins: If we do the multiple scopes, we need to define how to get all the versions of the property.
<iank_> fremy: Yes - that's another question, how do you read the values.
<iank_> TabAtkins: None of my proposals have to worry about what context the script is in.
<iank_> TabAtkins: Big problem is what happens w/ typed om.
<iank_> fremy: I don't have a good idea for that.
<iank_> TabAtkins: 2) Always use the context which the element lives within. This means always get the Light DOM version. Means that you can never set the :host of the shadow DOM.
<iank_> plinss: That seems not good.
<iank_> TabAtkins: I agrree its not great, but simple and pretictable.
<iank_> TabAtkins: Not sure which one I want to do.
<iank_> TabAtkins: If anyone has opinions let me know.
<iank_> TabAtkins: As far as I can tell that is the major issue.
<iank_> TabAtkins: Lets get our browser folks about how this should work.
<iank_> TabAtkins: At some point I'll commit text about how this should work.
<iank_> heycam: What happens with constructable stylesheets.
<iank_> heycam: What happens to style elements which haven't been inserted within the point yet.
<iank_> heycam: ... e.g. you can access these from the TypedOM for these.
<iank_> emilio: This is at specified value time, and the grammer isn't applied yet.
<iank_> TabAtkins: ... yes - only at computed value time this is applied.
<iank_> TabAtkins: I'm good with this issue then, can move only the next one.
<iank_> fremy: Last thing you proposed, it'll use the Light DOM reg., the advantage is that you can always use both. If you are within the light tree, you can't pass information into the shadow tree.
<iank_> fremy: Component - wants to have a custom prop e.g. --grid-type
<iank_> TabAtkins: You can still set it, it won't get corrected until it hits the shadow tree.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
4 participants
You can’t perform that action at this time.