[CSSWG] Minutes Cupertino F2F 2023-07-19 Part IV: Selectors, Syntax, Values [css-selectors] [css-syntax] [css-values]

=========================================
  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: Preserve invalid selectors inside forgiving selector
              lists (such as :is() and :where()) regardless of whether
              there's an & in them (Issue #8356: Consider preserving
              invalid selectors in :is() and :where())

CSS Syntax
----------

  - RESOLVED: Work on the problem of expressing ranges of children in
              selectors in a more intuitive way (Issue #4140: Make it
              easier to express ranges for <An+B> selectors)
  - There wasn't agreement on what the syntax should be to express
      ranges of children in selectors so discussion will continue
      during breaks at the F2F and this will be added back to the
      agenda when a proposal develops.

CSS Values
----------

  - RESOLVED: Add sibling-count() and sibling-index() to css-values-5
              ED (Issue #4559: Proposal: add sibling-count() and
              sibling-index())

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

Agenda: https://github.com/w3c/csswg-drafts/projects/38

Scribe: dbaron

Selectors
=========

Consider preserving invalid selectors in :is() and :where()
-----------------------------------------------------------
  github-bot: https://github.com/w3c/csswg-drafts/issues/8356

  emilio: For nesting, when you have an & in a nested selector, we
          resolved to preserve the invalid selector inside so that you
          could properly track whether there was an &. Makes sense.
          But inconsistent, in the sense that it's a weird special
          case. Would be more consistent IMO to preserve all invalid
          selectors. That way you don't special case nesting. It's
          also more consistent with @supports and @media,
          with <general-enclosed>.
  emilio: ...It feels more generally consistent. I don't think it
          matters particularly... I don't expect compat issues. The
          question is... as Oriol mentioned, this also makes the empty
          selector kind of silly.
  TabAtkins: As a selectors editor, I agree, would be good to keep it
             ??? defined.
  TabAtkins: not sure why we decided to drop the invalid selector
             arguments in :is()
  emilio: Implementation-wise, it's easier to just drop it, but if we
          need to preserve it, easier to preserve always rather than
          sometimes.
  emilio: So if nobody objects I think this would be better than the
          current specified behavior.
  <bramus> +1

  ntim: Isn't there something about forgiving parsing?
  emilio: That's the behavior of dropping invalid selector.
  TabAtkins: Nesting cares about whether there's an & at all, so you
             don't have a newer/older browser behavior switch.
  dbaron: So you would still be treating invalid selectors the same
  dbaron: just preserving them in the OM.
  TabAtkins: Yes
  emilio: Proposed resolution: preserve invalid selectors inside :is()
          and :where() regardless of whether there's an & token.
  matthieudubet: Do for all forgiving selector lists?
  TabAtkins: I think that's all of them for now, but we should say for
             all forgiving selector lists.

  RESOLVED: preserve invalid selectors inside forgiving selector lists
            (such as :is() and :where()) regardless of whether there's
            an & in them

CSS Syntax
==========

Make it easier to express ranges for <An+B> selectors
-----------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/4140

  SebastianZ: I previously suggested a new syntax for expressing An+B
              selectors in :nth-child() etc.
  SebastianZ: We were discussing this, we had 2 proposals. They seem
              orthogonal; we could have both. But I think one I
              suggested initially is targeting the most common use
              cases.
  SebastianZ: Tab was also mentioning some things.
  SebastianZ: reusing the range syntax from Media Queries, with one
              addition: adding a "last" keyword to count from the last
              element instead of the first.
  TabAtkins: The problem we're trying to solve is that right now a
             selector targeting a range of elements (e.g., 3rd through
             7th), it's possible to write using two :nth-child()s, but
             it's not obvious how, and tricky.
  TabAtkins: So the first thing we should agree on is whether to agree
             on developing a syntax to enable expressing ranges more
             easily.
  TabAtkins: And if so we have some suggestions to go over and
             possibly decide between.
  TabAtkins: I think it's a reasonably common case (e.g., "select the
             first 3 elements")
  TabAtkins: you have to write :nth-child(3-n) or :nth-child(-n+3).
             I'd prefer n <= 3, like you'd write elsewhere.
  <SebastianZ> See also
https://github.com/w3c/csswg-drafts/issues/4140#issuecomment-517857973

  TabAtkins: Do we think this is worth adding to selectors?
  florian: Yes
  <miriam> +1
  <oriol> +1
  fantasai: not sold on the syntax, but seems reasonable to come up
            with something
  <fremy> I have written code that would have benefited from this, so
          sympathetic
  <dbaron> +1 to working on the problem

  RESOLVED: Work on the problem of expressing ranges of children in
            selectors in a more intuitive way.

  TabAtkins: a few suggestions for syntax.
  TabAtkins: oriol suggested a different approach from what TabAtkins
             and SebastianZ are thinking about.
  TabAtkins: If you're expressing a range, do you want a range on the
             "n' variable or a range on the output?
  TabAtkins: You want a range on the output rather than the input.
  TabAtkins: If your range was 2n and your range is 1-5, are you
             selecting 2,4,6,8,10 or 2,4 ?
  TabAtkins: In this case you want 2,4
  <TabAtkins> 2n <= 5, for example, will return 2,4
  <TabAtkins> if a "<= 5" condition can return 6,8,10 I think that's
              super weird
  <astearns> range-limited output?
  TabAtkins: This ties in to what syntax we're using
  TabAtkins: I think if you see 2n <= 5, you expect all the values of
             2n that result in a value <= 5.

  emilio: Before anything else, can we agree on making it part of
          :nth-child() rather than inventing new pseudo-classes. I
          think it makes sense as part of :nth-child().
  TabAtkins: I think basically building this into An+B is good.

  oriol: I prefer my proposal -- when I started ??? with the An+B
         syntax, I first assumed that "n" would be strictly positive,
         then I thought all integers -- there's an implicit condition
         that "n" is nonnegative. I think this implicit condition may
         be confusing. I was thinking my proposal adding an explicit
         condition to n could make things more clear.
  oriol: That said, it may be true that the other proposal maybe
         covers more frequent cases in a shorter way.
  oriol: You can convert from the other proposal to mine by adding
         another :nth-child() pseudo-class. I'm not opposed to the
         other one.
  oriol: I think this is a good point that my proposal covers.
  <TabAtkins> my actual proposed syntax kinda splits the difference
              tho, I suppose: ranges must be simple, just a number and
              n. So `:nth-child(n <= 5)` only, not `2n <= 5`. If you
              want to both, `:nth-child(n <= 5):nth-child(2n)` or
              `:nth-child(n <= 5 of 2n)`

  myles: I think we've been reinventing list comprehensions that are
         in many proper programming languages. We should take
         something that already exists.
  TabAtkins: This is reinventing the range operators that some
             operators... different syntax space from list
             comprehensions.
  myles: I'm not saying to dump python's list comprehensions in CSS --
         but I'm saying for input vs. output do what the programming
         languages do.
  TabAtkins: I disagree with that on principle -- it's more like a
             range than a list comprehension.
  TabAtkins: the syntax affects whether your ranges are on the input
             on the output.
  TabAtkins: Different languages make map-then-filter or
             filter-then-map easier, and I don't think there's a clear
             reason to prefer one based on precedent.
  TabAtkins: My preferred syntax proposal makes this moot. Rather than
             full An+B combined with ranges is that when we do ranges,
             you're limited to N on one side, a number on one side ,
             and a sign in the middle. IF you want An+b stuff as well,
             you can do the same ?? as if you're combining 2
             conditions together. Not ??? An ???. I proposed we only
             allow n <= 5. You can decide whether you allow the first
             5 children that are also
  TabAtkins: even or the first five even children, depending on how
             you write it.
  hober: If I understand, I think I agree.
  <TabAtkins> `:nth-child(n <= 5):nth-child(2n)` or `:nth-child(n <= 5
              of 2n)`
  TabAtkins: We can rely on existing CSS facilities.
  <hober> the case I care about, I think, is something like "give me
          some things that match this selector, but give me at most N
          of them."
  <fantasai> that's :nth-child(An+B of <selector>)

  fremy: I think we're not going to have consensus today. But I want
         say I agree with following other languages. I think we should
         have multiple filters, applied in order author wrote them. I
         find it hard to understand "2n+3 < 5", no idea what it
         selects. I think we need something more clear.
  <ntim> +1 to fremy
  <TabAtkins> okay so that's `:nth-child(n <= 5 of 2n)`, exactly the
              same as `:nth-child(n <= 5 of .foo)` if you cared about
              foo-ness rather than even-ness
  fremy: :nth-child(2n) is for the even things, and then say first
         three.
  fremy: I think this reads better than the mathematic formula.
  fremy: I think 2n+1<5 is too difficult to understand.
  <ntim> I agree 2n+5 < 5 is hard to understand
  <TabAtkins> dangit, sorry, I meant of course `:nth-child(n <= 5 of
              :nth-child(2n))`

  SebastianZ: I want to note first proposed syntax also involves
              "last" keyword as said in beginning, which allows
              counting from the end. From 3rd element to 3rd-last
              element, style everything. Wouldn't be possible with
              second proposed syntax.
  TabAtkins: We could have negative indexes mean what they do in most
             programming languages.
  fantasai: But we don't do that now
  <fantasai> Like, I really love negative indexes representing from
             the end. But we don't do that now, and so I think it
             would be confusing to have it work for some things and
             not others
  <plinss> we do use it in grid
  <fantasai> plinss, good point :) but not in :nth-child(), and in
             fact some of the :nth-child() patterns rely on us not
             processing negative indexes :/
  SebastianZ: With the proposal of the "last" keyword we can also
              express ranges to an nth-last child. Tab said probably
              possible with second proposed syntax, but I don't think
              possible, but I disagree, since we're there focusing on
              the "n" which means the number of elements.

  <TabAtkins> once we drain the queue, I propose we take this back to
              the issue for syntax discussion

  oriol: With my proposal "n" is just the entity in the expression
  oriol: Going from the index of the last child ..
  oriol: If we want to express conditions to the end, constrain on the
         output seems more suited

  ntim: +1 to fremy about 2n+1 < 5 being hard to understand.
  ntim: Hope we don't end up with that

  <fremy> Can I suggest maybe to do like we did before in such cases,
          make a list of use cases, and then write how each proposal
          writes that range?

  fantasai: I was going to suggest table discussion until Friday.
            Tomorrow we'll have time for people to workshop ideas. We
            should do that tomorrow.
  TabAtkins: This is going too long, we should go back to the issue.

  SUMMARY: Will discuss syntax further in issue.

CSS Values
==========
  scribe: fantasai

Proposal: add sibling-count() and sibling-index()
-------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/4559

  [bramus explains the proposal]
  <bramus> https://gist.github.com/bramus/45878ffc94a7318d63eb83a8882dfcc2
  bramus: Right now they use various nasty selectors to achieve this
  bramus: It's really not great
  bramus: Something that we see authors do a lot is they have the need
          to have access to the value of n of nth child. They want to
          know on an element which n am I, and how many siblings are
          there. This is used for staggered animations, where every
          sibling has a little delay based on which child it is. Or,
          placing something around a circle - you need which item you
          are and how many items there are. Right now authors hack
          around this using nasty selectors
  bramus: I'm still proposing why authors need this

  argyle: There's lots of use cases.
  argyle: Dynamic color distances, dynamic [missed]
  argyle: recursion and tying things to position in the tree is fun
  argyle: sibling-index() and sibling-counter(), and child-count()
  argyle: these are static values that are about the leaf on the
          branch. They don't change, even if you change to display:none
  argyle: but gives many possibilities
  argyle: There's nasty selectors that do this, e.g. using
          :nth-child() with a lot of repetition
  argyle: also JS to do it, or template [missed]
  argyle: [explains how JS library works on this]
  argyle: New one recently proposed was child-count().
  argyle: sibling-count() and sibling-index() are directly related to
          my tree position. Not introducing cycles
  argyle: container's child-count() is what you get from JS, CSS
          doesn't affect it
  argyle: but doesn't fulfill every use case, so in some cases need a
          filtered index
  argyle: e.g. if you have 30 items and filtered to 15
  argyle: I guess I talked plenty

  emilio: Offhand this doesn't seem terribly problematic
  emilio: but it's not static
  emilio: not worse perf than :nth-child, but you need to invalidate
          anything that uses these functions whenever a sibling is
          added or moved
  emilio: not to say we shouldn't do it
  emilio: I'm a bit inclined to think that child-count() may not be so
          useful
  emilio: problem with child-count() is that you have to go through
          whole child array to compute it, which is also an issue with
          nth-child if you use it on every element ....
  emilio: needs to be optimized similarly to nth-child
  emilio: presumably these would go inside calc()?
  argyle: often
  <fremy> @ emilio, child-count() is useful if you want to divide a
          space or time (child-index() / child-count())

  emilio: Other question would be, right now a lot of things assume
          numbers are resolved statically
  emilio: e.g. at parse time
  emilio: so on one hand, feel that this would be easier
          implementation-wise if we did it like variables
  emilio: but matter of implementation complexity
  emilio: I think this will take a lot more time if we do it in calc()
          than if we do it like variables
  emilio: which... is fine.
  argyle: Let me show you a demo
  <argyle> https://www.irccloud.com/pastebin/EsOxTEIg/
  emilio: In variables, if you do like a custom property, then ? works
  <argyle> env()
  <argyle> yeah
  emilio: but then we need to keep things valid at parse time
  emilio: if you're using invalid stuff around sibling-index(), would
          have same error behavior as custom properties
  emilio: instead of falling back to previous declaration, you would
          get invalid-at-computed-value-time

  TabAtkins: I think this would be useful for reasons mentioned
  TabAtkins: only concern is implementation complexity and performance
  TabAtkins: e.g. this defeats style sharing
  TabAtkins: Discussing similar problem, dbaron explained the concerns
  TabAtkins: I'm not an implementer, can't express those concerns
             about perf. But there are performance footguns involved
             here
  emilio: The main perf issue, if you use sibling-index() etc., then
          every sibling gets its own style
  emilio: whereas if you do :nth-child(2n), then you can share styles
          between the things that match that rule
  emilio: It's not trivial to optimize it to preserve style sharing
  emilio: I guess :has() is worse
  TabAtkins: The things people do today, where people do explicit
             :nth-child()s, is just as bad
  TabAtkins: so the question is, would making this more likely to be
             used because it's easier?

  fremy: A lot of the ? are using this to make the demo work
  fremy: She has an inline style on every element that says, e.g.
         --index: 1; --index: 2; etc.
  fremy: what people do today is probably worse
  emilio: Main question is, does this make it too easy to do the wrong
          thing
  emilio: I'm not too concerned about style sharing in particular,
          more concerned about making it work in calc() or nth kind of
          thing

  emilio: Like attr(). It used to be a strongly-typed thing. Then we
          switched to more like variables
  emilio: we ended up deciding that fixing things was hard, so make it
          work like custom properties
  fantasai: You can't ever have an invalid output of siblings or
            sibling index
  TabAtkins: We changed attr() because you can have an invalid
             attribute that won't parse
  TabAtkins: having attr() as a length is more complex

  emilio: Well, it should be invalid for pseudo-elements
  emilio: What index would those be?
  emilio: it's not hard, it's a lot of work to fix

  <fremy> +1; sibling-index() in rgba() sounds like a great reason to
          make this a variable substitution
  <TabAtkins> nothing weirder about `rgba(sibling-index()...)` vs
              `rgba(sin(5) ...)`

  argyle: I'm curious about concatenation
  argyle: What if I want to create an ident that uses the
          sibling-index()
  argyle: is that invalid? it's not really a string I'm appending
  argyle: Also follow-up questions about nth-child syntax
  argyle: can I filter on a list and then get a sibling index of the
          filtered index
  argyle: to get the index after pre-filtering
  <bramus> seems like a follow up issue?
  fantasai: I can see the use-cases for that
  fantasai: like things with a [hidden], filter them out and use the
            index of what remains
  fantasai: you can't do an :nth-child() selector
  fantasai: but could do sibling-index(of <selector>)
  <argyle> this suffers from naive staggering
https://codepen.io/argyleink/pen/VwBKjwj
  <argyle> this was one of the most requested features at CSS Day
  fantasai: I can def see the use-cases, and the perf concerns
  fantasai: last time we had something with similar profile was
            :has(), which stayed as a draft for a decade
  <bkardell> More than a decade :)
  fantasai: So I feel like if we think this is a good idea but have
            perf problems, maybe we put it in Value 5 ED and note that
            it has perf problems and we're still deciding if it's good
            to add or not

  Rossen: So proposal is to add to work on Values module
  argyle: As an author you see :nth-child(), and think, I see you have
          that number. you know the number. Just give it to me. I want
          it.
  Rossen: any objections to adopt into Values 5, and then figure out
          if it's doable?
  dbaron: If we put it in a spec, likely to get implemented eventually
          even if 10-15 years later
  bramus: Authors want it. One of the most requested features
  bramus: #1 request at CSS Day
  bramus: People asked us to make it work
  Rossen: That's a pretty strong signal

  POLL: Add sibling-count() and sibling-index() to css-values-5 ED
  <fremy> yay, I think it can be made efficient
  <SebastianZ> Yay
  <argyle> yay
  <oriol> +1
  <miriam> +1
  <astearns> yea
  <fantasai> +1
  <bramus> yes
  <florian> oui
  <rachelandrew> yes
  <TabAtkins> yes
  <changseok> yay
  <Rossen> да
  <ntim> Yes, but only once we sort out how this works in calc
  <fantasai> ntim, it just returns a number, right?
  <TabAtkins> (my suggested names were sibling-index(),
              sibling-count(), child-count(), and tree-depth() )
  <hober> I don't think I can vote on this one way or the other
          without more data
  <argyle> just a number is all we need
  <tantek> +0

  RESOLVED: Add sibling-count() and sibling-index() to css-values-5 ED

  meeting day: end

Received on Sunday, 10 September 2023 15:24:14 UTC