Skip to content

[selectors] What is the reasoning for ignoring default namespaces only on the subject for :is() / :where() / :not()? #5684

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

Closed
emilio opened this issue Oct 29, 2020 · 8 comments
Labels
Closed as Question Answered Used when the issue is more of a question than a problem, and it's been answered. selectors-4 Current Work

Comments

@emilio
Copy link
Collaborator

emilio commented Oct 29, 2020

:is() / :where() / :not() have this sentence in them:

Default namespace declarations do not affect the compound selector representing the subject of any selector within a :is() pseudo-class, unless that compound selector contains an explicit universal selector or type selector.

I kinda get why that may be useful for :not() and why you might want it only on the rightmost compound. Though the behavior for :is() / :where() is a bit weirder, I feel like it'd be better to ignore the default namespace in the whole inner selector...

Or at least I don't see why you might want that behavior on :is() / :where()... And it'd be nice to make all three consistent (I don't have a strong opinion on the subject vs. whole selector for :not(), though it's better if they're implemented the same).

cc @andruud @tabatkins

@emilio
Copy link
Collaborator Author

emilio commented Oct 29, 2020

I guess the idea is that the default namespace for the compound has already been applied to the left of the :is effectively?

@emilio emilio added the selectors-4 Current Work label Oct 29, 2020
@emilio
Copy link
Collaborator Author

emilio commented Oct 29, 2020

For :not, it seems a bit weird because you're negating the default namespace, so I can see someone saying :not(.foo > .bar) to want .foo to include or not include the default namespace...

@emilio emilio added the Agenda+ label Oct 4, 2023
@tabatkins
Copy link
Member

I guess the idea is that the default namespace for the compound has already been applied to the left of the :is effectively?

Correct. The general intuition is that, given a selector AB, replacing that with A:is(B, C) should match all the same elements, and possibly more. If that line wasn't there, then going from svg|a:hover to svg|a:is(:hover, :focus) would cause the selector to stop matching anything at all when a non-SVG default namespace was in effect.

Same argument for the other combo pseudo-classes; they're all intended to be useful as syntax sugar, and ignoring the default namespace as specified is required for that to work intuitively.

(Hm, the same argument probably applies for :nth-child(); going from AB to A:nth-child(n of B) shouldn't reduce the number of matched elements. We should fix that.)

@tabatkins
Copy link
Member

And, uh, apologies for missing this three years ago, it had a very simple answer.

@Loirooriol
Copy link
Contributor

I think it can be confusing that the meaning changes depending on the context. Wouldn't it have been better to just drop

If a default namespace is declared, compound selectors without type selectors in them still only match elements in that default namespace.

Authors could use an explicit * to restrict to the default namespace if they wanted.

Possibly not web-compatible to change now, but I think default namespaces aren't actually used that much...

@tabatkins
Copy link
Member

Sure, changing that behavior would probably be better, but making a backwards-incompatible change was larger than what we wanted to do. If we think it's reasonable, tho, I'm fine with it.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [selectors] What is the reasoning for ignoring defaullt namespaces only on the subject for :is() / :where() / :not()?, and agreed to the following:

  • ACTION: TabAtkins to create a new issue for removing the rule
  • RESOLVED: Close issue #5684 with no change
The full IRC log of that discussion <Frances> Alan: Namespaces for :is() / :where() / :not()
<Frances> Emilio: Compact wise is probably okay, Tab's answer is good but weird that nested selector list has weird parsing behavior.
<Frances> Tab: Context if you write a selector without a namespace, with a url, will apply namespace to all selectors unless specifically overridden, even non type selector in the element name.
<TabAtkins> a.foo
<TabAtkins> a:is(.foo, .bar)
<TabAtkins> foo|a:is(.foo, .bar)
<Frances> Tab: Issue is if you start with a.foo and then want to have foo or a bar class, normally second selector matches same or more elements. In presence of default namespace selector, it might not.
<TabAtkins> foo|a.foo => foo|a:is(.foo, .bar)
<Frances> Tab: If it wasn't for the special case, they could get the default namespace rather than .foo namespace. Selector might not match anything. Do not apply now special namespace rule to their arguments.
<TabAtkins> foo|a.foo
<TabAtkins> foo|a:nth-child(n of .foo)
<Frances> Tab: Some related issues about other spots such as nth child of the selector. Expect to match all elements, with default namespace rule, it might not match anything.
<Frances> Tab: Alternative don't want backwards incompatible, can remove default namespace rule to only use when there is a type selector. Namespaces in general are rarely used across css, could fix by removing the special rule.
<Frances> Emilio: What is the implementation style of the rule?
<astearns> ack dbaron
<Frances> David: Probably well implemented for :not for the subject part of it. Referencing type selector, should be explicit about including universal selectors.
<Frances> Tab: default selector is a universal selector
<Frances> David: :hover and *:hover are weird.
<Frances> Oriol: If using featureless element, need to use universal selector to match them.
<Frances> Emilio: Only on quirks mode?
<dbaron> s/are weird/would now be different, which is a little weird/
<TabAtkins> :host *:host
<Frances> Oriol: For :hover, they are the same except for some cases can add universal selector to change the meaning.
<Frances> Tab: :host and *:host might not match a featureless element.
<Frances> Emilio: Ignore default namespace unless global or type selector.
<dbaron> s/Referencing type selector/When you talk about a type selector/
<dbaron> s/about including/about whether or not you're including/
<Frances> Tab: We can close the issue with no change and open another issue with changing the underlying rule entirely to be mutually exclusive with some of the other issues with the :is rule, need to be consistent and intuitive. Why do we have the rule in first place need to explain.
<Frances> Alan: Need to describe if backwards compatible.
<Frances> Emilio: Do we want it in the right most compound, why only in the right most compound?
<Frances> Tab: The one that is selecting the element, namespace rule probably invented to restrict to the default namespace, would make slightly harder to use the selector?
<Frances> David: Might be a function of how the selectors evolve over time, not taking combinators, and now taking them.
<Frances> Tab: Does make sense to apply to all components.
<Frances> David: rule to not apply to is part after last combinator makes sense.
<Frances> Tab: Intuition is to use :is and :where as syntax rules, such as preceding combinator, treated same as outer
<Frances> David: when there is a default namespace, should only be applied in one space in the selector, if overriding place in both spaces.
<Frances> David: right now outside of :where and not inside
<Frances> Emilio: :Has is different, is doesn't match. nth is different from :where. Interesting to see where in browsers it's implemented, possible non intentional implementation.
<dbaron> s/if overriding place in both spaces/so if you're overriding it you don't have to override it the same way in both places/
<Frances> Emilio: fine with no change, can address in another issue. Might not be specific to Firefox. We could try simplifying it.
<dbaron> David: also, regarding :has(), I can certainly see :has() working differently
<dbaron> s/space in the selector/place in the selector for a particular element/
<Frances> PROPOSAL: Close issue #5684 no change
<Frances> Alan: Can make the rule consistent, open a new issue on backwards compatibility or remove rule entirely
<astearns> ACTION: TabAtkins to create a new issue for removing the rule
<Frances> RESOLVED: Close issue #5684 with no change

@Loirooriol
Copy link
Contributor

BTW, this is implemented buggy in WebKit:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<style>
/*<![CDATA[*/
@namespace url("http://example.com/foo");
@namespace svg url("http://www.w3.org/2000/svg");
svg|svg { background: cyan }
svg|svg:is(:hover, :focus) { background: green }
/*]]>*/
</style> 
<svg tabindex="-1" id="svg" width="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"></svg>
</html>

The default namespace prevents :hover from matching, but :focus can match. It's the opposite for :is(:focus, :hover).

@astearns astearns added the Closed as Question Answered Used when the issue is more of a question than a problem, and it's been answered. label Jan 17, 2024
@dbaron dbaron changed the title [selectors] What is the reasoning for ignoring defaullt namespaces only on the subject for :is() / :where() / :not()? [selectors] What is the reasoning for ignoring default namespaces only on the subject for :is() / :where() / :not()? Mar 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed as Question Answered Used when the issue is more of a question than a problem, and it's been answered. selectors-4 Current Work
Projects
None yet
Development

No branches or pull requests

5 participants