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-scoping][selectors] Should :where(:host) work? #6420

Closed
LeaVerou opened this issue Jul 3, 2021 · 10 comments
Closed

[css-scoping][selectors] Should :where(:host) work? #6420

LeaVerou opened this issue Jul 3, 2021 · 10 comments

Comments

@LeaVerou
Copy link
Member

LeaVerou commented Jul 3, 2021

Currently, the root of a web component can only be selected via :host and its varieties (:host(), :host-context() etc). [spec]

Because :host has a specificity of 0,1,0, it can interfere with UA styles, such as those that set [hidden] { display: none }. For that reason, authors are instructed to explicitly account for that in every web component they write by adding this to the component's stylesheet:

:host([hidden]) { display: none }.

Not only is this a hassle for authors, but entirely unrealistic to expect that all authors will fall in line and follow this. In practice, we'll just end up with a lot of components that break hidden.
But even beyond the hidden attribute, it should be possible to specify host styles that do not override existing UA or author styles.

The whole point of :where() is to rectify exactly that kind of problem, however :where(:host) does not currently work. Is there a way to fix that?

cc @tabatkins

@emilio
Copy link
Collaborator

emilio commented Jul 3, 2021

I'm confused, how is this related to :where() at all? Any author selector will override UA styles, so this already doesn't work:

<!doctype html>
<style>
:where(.foo) {
  display: block;
}
</style>
<div class="foo" hidden>Can you see me?</div>

@tabatkins
Copy link
Member

Yeah, the hidden thing is an unfortunate consequence of the fact that the hidden attribute is simply broken, and always has been. There's nothing we can do to fix it, either, unfortunately; in particular, making the change requested here wouldn't do anything for it.

The host element not matching :where() is according to spec right now (nothing matches the element unless explicitly specified to do so), but :where() and :is() are definitely special-cases in that they're effectively selector grammar, not selectors themselves. I think it would be reasonable to allow them to match the host element, so long as one of their contained selectors does.

I don't know how UAs currently implement the featureless thing, tho, so I'm not sure if it's a big deal to extend to :where()/:is() or not.

@LeaVerou
Copy link
Member Author

LeaVerou commented Jul 3, 2021

Ah, right, brain fart, thanks @emilio.

Still, it would be good if authors were able to style :host but have their code be overridable by other author code, so original point still stands. At least that way the author can add [hidden] { display: none } and make it work again.

@emilio
Copy link
Collaborator

emilio commented Jul 3, 2021

:where wouldn't fix that either, since the rules from inside and outside the shadow tree are not sorted by specificity.

What you describe should already be working, as rules from outside the shadow tree go before (non-important) rules from inside the shadow tree:

<!doctype html>
<style>
  [hidden] { display: none }
</style>
<div id="host" hidden>Can you see me?</div>
<script>
  document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = `<style>:host { display: block }</style>`;
</script>

@emilio
Copy link
Collaborator

emilio commented Jul 3, 2021

I don't know how UAs currently implement the featureless thing, tho, so I'm not sure if it's a big deal to extend to :where()/:is() or not.

It'd be slightly annoying to implement the digging into :where / :is, specially since it'd be valid to do something like :where(:host, div) or something, and that is a bit tricky to reason about...

@LeaVerou
Copy link
Member Author

FWIW I ran into a use case today, involving custom selectors as well. I wanted to abstract away a certain aspect of my web component, so I tried defining these:

@custom-selector :--horizontal :is(
	:host-context(bar-chart:not([orientation])),
	:host-context(bar-chart:not([orientation])) *,
	:host-context(bar-chart[orientation="horizontal"]),
	:host-context(bar-chart[orientation="horizontal"]) *
);

@custom-selector :--vertical :is(
	:host-context(bar-chart[orientation="vertical"]),
	:host-context(bar-chart[orientation="vertical"]) *
);

But alas, it didn't work because :host-context() does not work in :is().

@emilio
Copy link
Collaborator

emilio commented Oct 19, 2021

:host-context is bad to begin with, see #1914.

@tabatkins
Copy link
Member

Closing as a dupe of #5093 .

@tabatkins
Copy link
Member

Never mind, not a dupe, just semantically close to what I was working on. ^_^

@tabatkins
Copy link
Member

Okay now it's fixed, by 066ede4.

(Logical combinations work on featureless elements, but still only match against the explicitly-defined set of selectors.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants