[CSSWG] Minutes Telecon 2022-06-01: Selectors extra call [selectors-4]

=========================================
  These are the official CSSWG minutes.
  Unless you're correcting the minutes,
 Please respond by starting a new thread
   with an appropriate subject line.
=========================================


Selectors
---------

  - RESOLVED: Remove special handling of :scope in :has() (Issue #6399:
              Remove the :scope dependency from the relative selectors
              definition)
  - RESOLVED: Remove special handling of :scope in relative selectors
              generally (Issue #6399)
  - RESOLVED: Disallow nesting :has() inside :has() (Issue #6952:
              Consider disallowing logical combination pseudo-classes
              inside :has())
  - RESOLVED: No change; :host etc. continues to be allowed inside
              :has() (Issue #7212: Consider disallowing :host, :host(),
              :host-context() inside :has())
  - RESOLVED: @supports uses non-forgiving parsing for all selectors
              (Issue #7280: Detecting :has() restrictions)
  - RESOLVED: Close no change (Issue #6845: Consider disallowing :has()
              outside the rightmost compound)
  - RESOLVED: Revert the resolution from #3760, removing the "no
              complex selectors" restriction from :nth-child() (Issue
              #3760: Defer complex selectors inside :nth-child() etc.
              to L5)

===== FULL MEETING MINUTES ======

+++ Selectors/:has() focused extra meeting +++

Agenda: https://lists.w3.org/Archives/Public/www-style/2022Jun/0001.html

Present:
  Adam Argyle
  Rossen Atanassov
  Tab Atkins Bittner
  David Baron
  Oriol Brufau
  Tantek Çelik
  Emilio Cobos Álvarez
  Elika Etemad
  Chris Harrelson
  Brian Kardell
  Brad Kemper
  Rune Lillesveen
  Jen Simmons
  Alan Stearns
  Miriam Suzanne

Scribe: fantasai

Selectors
=========

Remove the :scope dependency from the relative selectors definition
-------------------------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/6399

  futhark: :scope was specced to have a special meaning inside :has,
           that it matches the selector matched by :has() itself
  futhark: It would be much simpler it kept the same meaning as it has
           outside of :has()
  TabAtkins: Making :has() give a special meaning to :scope wasn't a
             definitive choice, it just fell out of the definitions we
             had
  TabAtkins: I'm comfortable with removing this
  TabAtkins: Just need to do some edits to definitions
  futhark: There are complexities when it complexities for allowing
           :scope inside :has()
  futhark: It'll be easier to handle cases wrt shadow hosts if we make
           this change
  <TabAtkins> Yeah, :scope was invented for querySelector anyway, I'm
              comfortable boxing it off for just that purpose.
  fantasai: I think to the extent we might need such a functionality,
            we can choose a different syntax for it
  <emilio> +1

  RESOLVED: Remove special handling of :scope in :has()

  TabAtkins: I would prefer to remove it for relative selectors in
             general, and redefine :scope to just be for .querySelector
  TabAtkins: I think we'll run into these problems in the future
             otherwise

  RESOLVED: Remove special handling of :scope in relative selectors
            generally

  futhark: Issue 7211 looks related
  astearns: Let's skip, I'll add a comment pointing to this resolution

Consider disallowing logical combination pseudo-classes inside :has()
---------------------------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/6952

  futhark: I think there is agreement to allow combinations like :is()
           and :where()
  futhark: But implementors want to disallow :has() inside :has()
  bkardell: I think that's my impression as well. I think Safari
            implements this way as well
  futhark: Implement in chrome and safari, but buggy
  futhark: Don't think need to change the spec at this point
  futhark: or to add any limitations, other than :has()
  TabAtkins: I support this
  <jensimmons> I've already found a useful usecase for
               figure:not(:has(:not(img))) { ... }

  fantasai: Proposed then that :has() cannot be nested inside :has()
  oriol: I think other combinations seem useful, but :has() inside
         :has() doesn't seem that useful
  bkardell: Originally wanted to disallow all of them, but based on
            feedback went back and made them work
  bkardell: said some perf implications, but seem livable-with
  bkardell: so let's just prohibit :has() inside :has()
  astearns: Other opinions?

  RESOLVED: Disallow nesting :has() inside :has()

  <TabAtkins> I mean, I'm sure there are use-cases for nested :has(),
              but they're not as obvious and clearly worth the
              complexity cost, so I'm happy with this.

Consider disallowing :host, :host(), :host-context() inside :has()
------------------------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/7212

  futhark: Given resolution wrt :scope, at least from Chrome side, we
           agree that :host-context will never match inside :has()
           because it needs to have sibling/parent ... shadow tree
  futhark: not a perf problem, but it will never match
  futhark: Proposed resolution from our side is no change

  TabAtkins: :host will never match as final selector, but the example
             here ...
  <TabAtkins> .b:has(:host .a .c)
  TabAtkins: slightly simplified version of a selector in the issue
  TabAtkins: this would still match
  TabAtkins: However it's exactly equivalent to just moving the :host
             outside
  TabAtkins: If we were to ban it, wouldn't hurt anything, but is
             matchable in this instance
  bkardell: Because doesn't begin with a relative combinator
  TabAtkins: So evaluates globally against the context
  bkardell: This is where the whole weird context comes from
  bkardell: I think a lot of ppl would not expect that to match
  futhark: From impl side of things, it's not an important issue
  futhark: Removing special meaning of :scope means it's not a perf
           issue
  bkardell: So you would ... walk all the way up the tree?
  bkardell: Seems weird to me that this should match
  bkardell: Basically nobody would expect it
  TabAtkins: It's the same as putting :root in there
  TabAtkins: Why expect not to match?
  bkardell: Even in jquery etc., :has() you start matching at the
            boundary, you don't walk all the way up the tree
  TabAtkins: Am I misremembering this?
  <fantasai> :has(:is(:host .a))
  <fantasai> maybe you mean something like that?

  fantasai: The host element doesn't necessarily have to be inside...
  fantasai: The host doesn't have to be in the :has()
  fantasai: When you have :is() tho, that doesn't necessarily get
            scoped.
  fantasai: So if you nest it like this, this could match.
  <fantasai> :has(:is(:root .a)) would match, for example
  TabAtkins: That's right, would do it
  fantasai: My inclination is to make this invalid, would be easier for
            everyone to understand and get it right
  astearns: You would get the same effect by moving :host outside of
            :has()
  TabAtkins: Yes
  <TabAtkins> A:has(:is(:host B)) rewrites to
              :is(:host A, A:host):has(B)

  bkardell: Previous example was one that Oriol pointed out. Did we
            agree to the opposite, that you can't use :is()? or did I
            misunderstand?
  TabAtkins: All other relational selectors are fine
  bkardell: What was proposal?
  TabAtkins: Make :host illegal inside of :has() context
  emilio: If no reason to disallow performance-wise, probably more work
          to disallow. But don't mind either way
  futhark: I don't have strong feelings either way
  astearns: Given confusion we just put ourselves through, I have a
            slight preference for disallowing
  astearns: because it's an unreadable way of expressing this
  bkardell: I agree
  TabAtkins: :host does have theoretical use in here, because if you
             want to select a top-level element in your shadow tree
             need to use ':host > element'
  TabAtkins: it's no more confusing than :root in this context
  TabAtkins: so that part doesn't bother me

  emilio: Why would you want to use direct child combinator? You can't
          have anything that's direct child of host in here
  bkardell: ...
  emilio: so :host :has(stuff)
  emilio: You would need to be :host(:has())
  <TabAtkins> .foo:has(:is(:host > .top-level .bar))
  TabAtkins: This is a meaningful selector
  TabAtkins: it's a .foo that has a non-top-level-.bar inside it
  emilio: Yeah, ok, fine
  emilio: Assuming there's no reason to ban it perf-wise, then seems
          fine to keep it

  astearns: I'm hearing a lot of "eh"
  TabAtkins: I suggest we leave as-is, unless on further investigation
             it has a perf implication
  <emilio> +1
  futhark: I agree

  RESOLVED: No change; :host etc. continues to be allowed inside :has()

Detecting :has() restrictions
-----------------------------
  github: https://github.com/w3c/csswg-drafts/issues/7280

  emilio: It seems this is not going to have so many restrictions, so
          maybe not a big deal
  emilio: In case we wanted to restrict stuff like :host
  emilio: and then eventually potentially ...
  emilio: Not easy to detect which UAs would support it vs not
  emilio: since :has() uses forgiving parsing, anything you throw at it
          is valid
  emilio: It seems we're only going to restrict :has() inside :has()
  emilio: doesn't seem useful but complex, but may still matter...
  emilio: My point is that if we have any hope for unrestricting, it
          may be useful to be able to detect it when we do
  <jensimmons> +1000
  emilio: If you put @supports :has(:has()) ...
  emilio: makes it a problem if you want to do something in the future
  emilio: you can always test the thing inside

  TabAtkins: Not true
  TabAtkins: :is()-disallowed pseudo-elements, for example
  TabAtkins: This sounds reasonable to me
  TabAtkins: Unsure about forgiving vs unforgiving

  jensimmons: I think it's a really good idea
  jensimmons: Having @supports parse as valid a thing that the browser
              doesn't support
  jensimmons: for the future, we need @supports to be accurate and true

  emilio: For FF it's easy, just passing down a flag
  oriol: I wonder if rather than adding hack in supports we could say
         that if you have either :has() or whatever that has this
         forgiving syntax, and all of the selectors inside it are
         invalid, then it would also be invalid
  oriol: It would be something like, if you have some invalid and some
         valid treat whole as valid
  oriol: So if you only have invalid ones, it would be invalid. If you
         have a mix, it would be valid
  oriol: So if using :has(invalid) then is invalid, and detect that
         without having to make supports change the syntax
  <emilio> oriol is saying that `:has(:random)` would be valid, but
           `:has(something, :random)` would be valid

  fantasai: OK, so I'm with jensimmons here. If the selector contains
            anything invalid, then it should return as invalid even if
            the invalidity is caught at a lower level
  emilio: Some precedent here wrt -webkit- stuff
  jensimmons: If this occurred to me as a developer, I wouldn't look it
              up. I would use @supports to detect support, e.g with
              color:red
  emilio: Especially if CSS author, unlikely to jump to using JS to
          check

  astearns: So proposed resolution is for @supports to use
            non-forgiving parsing for all selectors
  TabAtkins: yes
  <fantasai> strong +1

  RESOLVED: @supports uses non-forgiving parsing for all selectors

Consider disallowing :has() outside the rightmost compound
----------------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/6845

  futhark: raised by anttijk to [missed]
  futhark: Proposal is no change
  futhark: Safari doesn't have this restriction, and there are ways to
           optimize
  <fantasai> https://github.com/w3c/csswg-drafts/issues/6845#issuecomment-998484450
  astearns: Proposed resolution is no change

  RESOLVED: Close no change

Defer complex selectors inside :nth-child() etc. to L5
------------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/3760#issuecomment-1119234126
  scribe: TabAtkins

  fantasai: We had agreed to defer complex selectors inside
            :nth-child() until level 5
  fantasai: and :is() and :where(), etc
  fantasai: It seems like it's been implemented in
            :is()/:where()/:not() though
  fantasai: So I committed the edits to restrict it for
            :nth-child()/etc, but not for the others that have already
            implemented it.
  fantasai: So I want to know if we really do want this restriction for
            :nth-child(), or if impls are okay with just allowing
            complex selectors.
  fantasai: Oriol had a question about nesting :nth-child(... of
            :is()), the restriction would be recursive.
  astearns: So both those examples would be invalid?
  fantasai: Yes.
  fantasai: Or both valid, depending.
  fantasai: So question is, what do impls want to do?

  emilio: Since Blink and Gecko don't yet implement the "of <selector>"
          at all yet, I'd be okay with moving it to level 5. But we
          should implement it.
  fantasai: Note that this just about complex selectors in "of
            <selector>"
  fantasai: Not the general feature
  fantasai: so :nth-child(1 of .foo) would be valid in level 4, but
            :nth-child(1 of .foo .bar) would be invalid
  emilio: Don't think it matters much either way. When we get to
          implement it we'll probably do the complex selector form.
  emilio: Guess it matters how much it matters for Selectors 4 to have
          multiple interoperable impls, but we don't implement the
          simple selector syntax either in Gecko.
  <bkardell> +1 to move it to level 5

  fantasai: Opinions from the Safari team?
  jensimmons: I think we've already implemented it
  TabAtkins: I know Safari has done at least simple selectors, dunno
             about complex
  <fantasai> https://www.software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cstyle%3Ep%3Anth-child(1%20of%20body%20%3E%20p)%20%7B%20background%3A%20yellow%3B%20%7D%3C%2Fstyle%3E%0A%0A%3Cp%3Estylethis

  astearns: In terms of spec advancement, punting complex selectors
            means we could promote level 4 as soon as simple selectors
            are done by multiple impls. But it's not clear to me if
            that's actually going to happen before complex is also
            supported.
  fantasai: It seems like webkit supports complex selectors in
            :nth-child()
  fantasai: So question is just to other impls - do you want to tackle
            complex selectors when you do the feature at all? Or do it
            stepwise?
  futhark: Don't have thoughts about it right now.
  emilio: Same
  emilio: I don't see anything terrible complicated about supporting
          complex selectors.
  emilio: Might make the invalidation a little trickier, but probably
          not by much.
  fantasai: Okay so if we don't know, and Safari has already done it, I
            suggest we remove the restriction.
  <bkardell> ok
  fantasai: If we need to add the restriction later we can do that.
  emilio: Sounds good.

  astearns: so proposed resolution is to undo the previous resolution
            and put complex selectors back into :nth-child(), until we
            see that this is a blocker for level 4 advancement
  astearns: Objections to reversing the previous resolution? (in
            issue 3760)

  chrishtr: Rune can you confirm if this is implemented this way in
            Chrome at the moment?
  futhark: We don't implement the "of <selector>" at all in Chrome yet
  TabAtkins: Right now everyone supports :th-child(), only safari
             supports :nth-child-(.. of selector)
  TabAtkins: We have a resolution on the books to restrict that
             selector to compound selectors
  TabAtkins: We're reversing that resolution
  chrishtr: So that won't have any effect on chromium and gecko
            shipping :has(), and forward compatible with us shipping
            the upgraded :nth-child() in the future
  TabAtkins: yeah
  chrishtr: So this is kinda just a technicality?
  astearns: Yeah just level wrangling
  astearns: Either we get a second impl of this in :nth-child(), or we
            get really close with everything else in level 4 and we
            defer *all* of the :nth-child() enhancements to advance the
            spec
  emilio: Or we get a second impl but that only did simple selectors,
          we could punt the complex selectors again. But doesn't matter
          much for impls right now.
  chrishtr: Sounds fine, doesn't affect our current impl plans.
  astearns: So, any objections?

  RESOLVED: Revert the resolution from #3760, removing the "no complex
            selectors" restriction from :nth-child()

Issue look-through and next steps
---------------------------------

  chrishtr: Checking - we resolved all the items in this list?
  astearns: Yeah. (Some discussion about 3 and 1 being identical.)
  chrishtr: So all the issues blocking Chromium shipping have been
            resolved, this is amazing.
  chrishtr: Does anyone disagree? Any other issues outside this list?
  astearns: Separate issue if we want an official CSSWG resolution if
            it's okay to ship :has() even though the spec isn't
            advanced enough.
  chrishtr: Yeah just wondering about further technical issues that
            need discussing.
  astearns: You had the list of four, I found all the other
            :has()-related ones. All of them afaik
  emilio: Impl wise, there's only a matter of fixing support.
  emilio: Seems like this is tested and impls are interoperable, then
          it's useful
  emilio: I'm not sure if this should be in the spec, but given that
          perf of :has() is kinda a blocker in general...
  emilio: Like it needs to be interoperable to be useful.
  emilio: I'm aware of engines doing various optimizations, wondering
          if spec should say something about the complexity of matching
          :has()
  emilio: Even though the various impl optimizations are impl details,
          wondering if the spec should mention something about that.
  astearns: Also wondering if there should be tests for particularly
            tricky perf situations.
  astearns: Don't think WPT has a way of testing CSS perf.
  bkardell: They can time out and get flaky, at least.
  <TabAtkins> You can explicitly do timing, if you want. Just gotta
              write it explicitly.
  emilio: I think we have test like that for CSS var() expansion limit.
  bkardell: Unsure we can agree what's a "complex case" tho.
  emilio: :has() is quadratic or exponential by definition, basically.
          Everything we don't optimize is going to be worst-case
          complexity.
  [missed from emilio due to dog]
  astearns: If there are particular perf issues you're worried about,
            good to raise issues on the spec about if we need to handle
            certain edge cases.
  astearns: Can decide if this is an impl-specific thing, or if we do
            need it in the spec.
  astearns: If there are gotcha that every impl should handle, that
            should be in the spec.
  emilio: For some kind of UAs, it may not be a big deal, only for live
          UAs.
  bkardell: Yeah like Prince probably doesn't care nearly as much.
  TabAtkins: If you have particular concerns of things to point out,
             we're happy to put notes for implementers in the spec
  emilio: Sounds good, mostly just an idle thought.

  astearns: Any other :has() discussion?

Received on Thursday, 2 June 2022 00:24:22 UTC