-
Notifications
You must be signed in to change notification settings - Fork 668
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-scoping-1] Specificity of :host, ::slotted, and :host-context doesn't seem to be defined? #1915
Comments
My thought was just that it would have the standard specificity of a pseudo-class, and the contained selector wouldn't matter; that's why nothing else is specified, so it's covered by the Selectors default. |
That definitely works for me, but it's not what Blink implements, nor WebKit, cc @rniwa |
@lilles do you have any opinion here? |
Having the same specificity for the two rules below sounds unfortunate to me as I can imagine you'd want to do host overrides on classes/attributes on the host element, but I don't know to what degree it's used in practice: :host(.pink) { color: pink } |
I have seen pairs of |
The Working Group just discussed
The full IRC log of that discussion<dael> Topic: Specificity of :host, ::slotted, and :host-context doesn't seem to be defined?<dael> github: https://github.com//issues/1915 <dael> emilio: Also if we want to keep it. Per spec this has spec of normal pseudo class, but there's a request to effect specificity of selector. I Impl the spec, but blink and webkit don't touch slotted....whatever we decide I'm fine. <dael> TabAtkins: Should be consistent. <dael> Rossen: Anyone have a preference? <dael> rune_: I can't see why we would do it differently <dael> dbaron: pseudo class vs pseudo element? <dael> TabAtkins: No, a selector with a pseudo eleemnt add specififity. <dael> dbaron: Match different things. <dael> emilio: slotted does that. <dael> dbaron: Add pseudo elements to specificity <dael> TabAtkins: Like pseudo class when you can opt in to specila specificity <dael> TabAtkins: Should change selectors to ask spec of pseudo element defaulting to none at all. <dael> TabAtkins: Servo asked for it explicity with a similar example. <TabAtkins> https://github.com//issues/2271 <dael> TabAtkins: I'm okay resolving that we make all these psuedo classes have the specificity of their elements and clarify pseudo elements can have the specificity. <dael> dbaron: The reason pseudo elements don't have specificity if you have a :before nothing before cna matc so there's no point in changing specificity when you have exactly one. You can change pseudo elements to have a class level specificity. <dael> TabAtkins: Seems fine. <dael> Rossen: Prop: <dael> emilio: Accounting for the specificty of the selector item and change the spec to say pseudo elements have same specificy of pseudo classes. <dael> emilio: If you have slotted div the spec would be the class? <dbaron> Interesting, CSS1 said pseudo-elements count as *elements*: https://www.w3.org/TR/CSS1/#cascading-order <dael> TabAtkins: It would be the same. <dael> emilio: Override it. <dael> Rossen: Objections? <dael> RESOLVED: Account for the specificity of the selector item and change the spec to say pseudo elements have same specificity of pseudo classes. |
…city. As resolved in w3c/csswg-drafts#1915. Differential Revision: https://phabricator.services.mozilla.com/D1849 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1454165 gecko-commit: ca14c36e4280927a10e43e95b8f459e767fc8178 gecko-integration-branch: autoland gecko-reviewers: xidorn
…ctor's specificity. r=xidorn As resolved in w3c/csswg-drafts#1915. Differential Revision: https://phabricator.services.mozilla.com/D1849 --HG-- extra : moz-landing-system : lando
…specificity. As resolved in w3c/csswg-drafts#1915. Bug: 1454165 Reviewed-by: xidorn Differential Revision: https://phabricator.services.mozilla.com/D1849
…ctor's specificity. r=xidorn As resolved in w3c/csswg-drafts#1915. Differential Revision: https://phabricator.services.mozilla.com/D1849
…city. As resolved in w3c/csswg-drafts#1915. Differential Revision: https://phabricator.services.mozilla.com/D1849 bugzilla-url: https://bugzilla.mozilla.org/show_bug.cgi?id=1454165 gecko-commit: ca14c36e4280927a10e43e95b8f459e767fc8178 gecko-integration-branch: autoland gecko-reviewers: xidorn
@lilles could we get this fixed in Blink? (I can submit a patch for it if you want). We already got a report due to this behavior change in Gecko not behaving as Blink: https://bugzilla.mozilla.org/show_bug.cgi?id=1492071 |
Oh, the incompatibility is more subtle: <!doctype html>
<div id="host"></div>
<script>
host.attachShadow({ mode: "open" }).innerHTML = `
<style>
:host div[foo] {
width: 100px;
height: 100px;
background: green;
}
div[foo] {
background: red;
}
</style>
<div foo></div>
`;
</script> Gecko shows green because it accounts the Is this expected? I'd expect the specificity to be added, and thus |
Turns out I had reported this to blink before... https://bugs.chromium.org/p/chromium/issues/detail?id=857415 |
FWIW, WebKit also renders it green. |
Yeah, I gave up and fixed it on Blink, before it keeps biting us. |
Regarding inner specificity, this is what's specified for :matches() and :not(). I could not find a spec'ed specificity for :host(). |
What's special about :host is that it's both functional and a single pseudo class, so not having the same specificity for the selectors below would be strange?
|
I think it would though, wouldn't it? The specificity of |
In any case, I agree this is inconsistent with So it makes more sense IMO to treat it as |
I'm fine with whatever includes the specificity of the sub-selectors, but I think we need to explicitly specify it in the spec. The non-functional :host follows from pseudo class specificity, but :host() doesn't, I think. |
Yes. There is also ::slotted() which is a pseudo element. Is there a separate issue for that one? |
I don't think so, guess we can discuss it here as well. Though I think |
That is true. Whether we add a pseudo element specificity for ::slotted() doesn't matter, but the spec needs to say that the selector inside ::slotted() contributes to specificity. |
@rniwa any opinion? |
The CSS Working Group just discussed
The full IRC log of that discussion<dael> Topic: Specificity of :host, ::slotted, and :host-context doesn't seem to be defined?<dael> github: https://github.com//issues/1915 <dael> emilio: We resolved on :host and ::slotted for specificity of inner selector. Should :host account for own specificity? There's incompat. Should :host* be same as :host-context*? <emilio> s/:host-context*/:host(*) <dael> Rossen_: Does anyone have an opinion? <fantasai> Quesiton was whether :host(*) should be the same as :host <dael> emilio: Should specificity of functiona host selector be only the selector or selector+pseudo class for specificity. I think 2nd. That is consistent and increases specificity of the selector. <fantasai> s/:host/*:host/ <dael> TabAtkins: This is inconsistent with :matches, but host on its own just making a * argument should be 0 makes me lean toward your argument. <dael> emilio: Works great <dael> Rossen_: Other opinions? <bkardell_> that's a new precident right? <fantasai> fantasai: +1 from me <dael> Rossen_: Objections? <bkardell_> nothing else works like that I think? <TabAtkins> bkardell_: Yeah, new precedent, kinda sorta. <dael> bkardell_: It's the only decision that makes sense, but it's new. NOthing else works this way today. <dael> emilio: Yeah, don't have many psuedo classes with selector arguments. <bkardell_> +1 <bkardell_> it makes sense <dael> Rossen_: Makes sense as a pattern going forward. <TabAtkins> I mean, :matches()/:not() mean *absolutely nothing* absent their selector; there's nothing there otherwise. :host *does* affirmatively select an element all by itself, and then the selector narrows it down. <TabAtkins> Proposed resolution: specificity of :host() is 1 pseudoclass + specificity of argument. (Not just specificity of argument.) <dael> RESOLVED: Specificity of :host() is 1 pseudoclass + specificity of argument. (Not just specificity of argument.) |
The CSS Working Group just discussed The full IRC log of that discussion<emilio> Topic: :host-context<emilio> github: https://github.com//issues/1915 <fantasai> emilio: When looking into this stuff, what I didn't implement which Apple also doesn't, is because it's really slow <fantasai> emilio: Reason why it's really slow is that for every class change, you either need to store everything for the whoel docuemnt, or you need to look at every shadow root that has a host context selector, and go through all the shadow roots inside your subtree to check if they have a relevant host-context rule... <fantasai> emilio: Handling DOM changes when host-context selectors are involved <fantasai> emilio: Blink solves this by doing subtree restyles? <fantasai> futhark: So in Blink we aggregate style info at the docuemnt scope for everything <fantasai> futhark: we don't use subtree calc <fantasai> futhark: We invalidate inside the shadow root <fantasai> futhark: We use a flag for it <fantasai> emilio: One of the nice things in our impl is that the style info inside the shadow root is contained <fantasai> emilio: Blink wants to make such a change, too <fantasai> emilio: So effectively it's similarly slow as /deep/ <fantasai> emilio: Since I haven't seen anything in Bugzilla requesting it <fantasai> emilio: And WebKit also hasn't implemented <fantasai> emilio: So would like to drop <fantasai> futhark: I don't have the usage numbers... <fantasai> TabAtkins: We should see if it's used <fantasai> TabAtkins: It offers a useful functionality but if ppl aren't suing it, I"m fine with dropping it <fantasai> Rossen: So, collect data, come back and based on this we can move forward <fantasai> fantasai: So maybe flag for next F2F so we don't forget <fantasai> Rossen: Hope to get to it before |
In Chrome, using Is that consistent with the currently specified behavior, or is this a Chrome-specific issue? It’s not clear to me from reading this thread what the decision was. |
Yep, global styles are higher specificity than |
Strictly, specificity is not the correct term here, it's about the cascading order and the cascade criteria added here: https://drafts.csswg.org/css-scoping/#shadow-cascading
|
Yep, I was talking about scenarios where the slot content belongs to one shadow (with the reset adopted) and the slot (and the use of This behavior seems to mean a lot of what would normally go in a generic, shared reset sheet isn’t viable with custom elements unless one can say for sure that they don’t and will never need to (for example) set a border color on a slotted input element or a font-weight on a slotted h2. However I see now that this isn’t the same as the issue this thread concerns. Thanks for clearing it up. |
See also: #3995 |
…ctor's specificity. r=xidorn As resolved in w3c/csswg-drafts#1915. Differential Revision: https://phabricator.services.mozilla.com/D1849 UltraBlame original commit: ca14c36e4280927a10e43e95b8f459e767fc8178
…ctor's specificity. r=xidorn As resolved in w3c/csswg-drafts#1915. Differential Revision: https://phabricator.services.mozilla.com/D1849 UltraBlame original commit: ca14c36e4280927a10e43e95b8f459e767fc8178
…ctor's specificity. r=xidorn As resolved in w3c/csswg-drafts#1915. Differential Revision: https://phabricator.services.mozilla.com/D1849 UltraBlame original commit: ca14c36e4280927a10e43e95b8f459e767fc8178
@lilles how can solve this situation? <style>
/* extract from reset.css */
h1 {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
</style>
<fancy-heading>
# shadow-dom
<style>
::slotted(h1) {
font-size 2rem;
margin-bottom: 1rem;
}
</style>
#/ shadow-dom
<h1>My title</h1>
</fancy-heading> You can't override that from the I guess that should be a way to win this war from the web component to avoid side effects. At least, Full example here: https://webcomponents.dev/edit/eQFJPlOvQMIuUZj71ohV/README.md |
If you want to override it from the component, that's what |
Then I will have mi components styles plenty of And If I open muy styles with I had to move all elements from light DOM to shadow DOM to ensure styles are applied without external surprises because I don't want to have my code plenty of I guess it was not well resolved the style management of the light DOM. Or at least the spec is not clear and all devs I ask thought that I hope we can define other way in the future to improve de Developer Experience. |
That indeed makes for some truly terrible developer experience for custom elements using ShadowDOM, as it would require me to rewrite all my styles that use Edit: For the record, yes I do believe global stylesheets should be able to override the styles as result from ::slotted, slottables are just LightDOM after all, but only if those selectors have higher specificity than the specificity of the ::slotted selector. Use case here, taken from an accordion webcomponent https://lion-web.netlify.app/components/content/accordion/overview/ , where accordion content and invoker is passed as content projection through slots: .accordion ::slotted([slot='invoker']) {
margin: 0;
}
.accordion ::slotted([slot='invoker'][expanded]) {
font-weight: bold;
}
.accordion ::slotted([slot='content']) {
margin: 0;
visibility: hidden;
display: none;
}
.accordion ::slotted([slot='content'][expanded]) {
visibility: visible;
display: block;
} becomes: .accordion ::slotted([slot='invoker']) {
margin: 0 !important;
}
.accordion ::slotted([slot='invoker'][expanded]) {
font-weight: bold !important;
}
.accordion ::slotted([slot='content']) {
margin: 0 !important;
visibility: hidden !important;
display: none !important;
}
.accordion ::slotted([slot='content'][expanded]) {
visibility: visible !important;
display: block !important;
} That also means that if I have a web component extension class that wants to extend my component with overrides, they themselves will be forced to do the same thing as well. I would definitely prefer it if:
Similar to |
@jorenbroekema other way is to use custom properties everywhere because I just tested, and once you put It's really painful if you want to build a Design System using the light DOM. It seems standard is forcing us to put all the content in the shadow DOM, with its problems. Then we will need declarative Shadow DOM, SSR, etc... |
Yeah that's a big downside since you want your users to do styling overrides on LightDOM, as this is basically their content, their territory.. So correct me if I'm wrong but you have to choose between:
.accordion ::slotted([slot='invoker']) {
margin: var(--accordion-invoker-margin, 0);
} |
I mean, the way For the example of the accordion, it probably makes sense that, given hiding stuff is core to it, Anyways, it seems to me like if the current model doesn't solve some of the use-cases, those should probably be discussed in a separate new issue, rather than a 4 year old closed issue. |
Here other example. You have some generic styles for headings, paragraph, etc.. to ensure your web looks fine. I wants component called hero for the home page or a card to list products. The will have a heading inside. I could style this elements because of the generic selector styles. <fancy-hero>
<h1>My site is awesome</h1>
<h2>It use Web Components</h2>
</fancy-hero>
<h2>My products</h2>
<ul>
<li>
<fancy-card>
<h3>Product one</h3>
<p>A really cool product description</p>
</fancy-card>
</li>
</ul> Currently, you have to put important in all styles of your component that apply to avoid being apply to the elements inside your components. If you try to upgrade a legacy project with tons of css your components are very fragile. And PD: I will create a new issue to discuss this use case |
One of the main reasons why I dislike Imagine a web component and an extension of it: class FooExt extends FooEl {
styles() {
return `
${super.styles}
::slotted(#foo) {
border-color: green !important;
}
`;
}
} The border color will only be green if this CSS part is later in the cascade than Edit: sorry I meant to write this on the more recent open issue, didn't mean to revive this closed one :( |
Which is important for cascade order.
I think there are similar issues with other selectors like
:matches
and such, but those seem to have been resolved (I think?) and now matches is defined as:Anyway. Blink calculates it dynamically based on the biggest specificity of the compound selectors that match. But as far as I can tell there's no spec that defines this (sorry if I overlooked it).
There's a problem with calculating specificity dynamically, which is that doing it converts the specificity not in just a function of the selector, but also in a function of the element, which is unfortunate (specially since that affects style sharing, since you can't assume that proving you match all the same selectors you have the same style, you also need to prove you match the exact same sub-selectors).
Also, doing it in a way that is not inconsistent requires matching through all the selectors, instead of just one, which isn't particularly great, but also not a big deal I suppose.
The text was updated successfully, but these errors were encountered: