[CSSWG] Minutes CSS Nesting Breakout 2023-04-05 [css-nesting]

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


CSS Nesting Breakout
--------------------

  - RESOLVED: Redefine CSSRuleList as ObservableArray (Issue #8350:
              Consider using ObservableArray<CSSRule> instead of
              CSSRuleList)
  - TabAtkins will file issue about CSSStyleDeclaration's array upgrade
  - RESOLVED: If naked property declarations inside @media become a
              thing, they are wrapped in a & {} rule (Issue #7850:
              CSSOM for nested media query rules)
  - fremy or plinss will file issue about whether naked declarations
      get sorted to the top of the list or not
  - RESOLVED: Close no change (Issue #7803: Nesting conditional rules)
  - We will retain the bare & supports strategy in the spec (Issue
      #8399: Feature detection for nesting)
  - The lookahead proved viable for issue #8249 (Problem with mixing
      properties and selectors). Discussion will continue on github as
      to the final decision between the provided options.

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

Agenda: https://github.com/w3c/csswg-drafts/issues?q=is%3Aopen+is%3Aissue+label%3AAgenda%2B+label%3Acss-nesting-1

Present:
  Tab Atkins
  Emilio Cobos Álvarez
  Tantek Çelik
  Matthieu Dubet
  Elika Etemad
  Daniel Holbert
  Brad Kemper
  Peter Linss
  Eric Meyer
  François Remy
  Cassondra Roberts
  Jen Simmons
  Alan Stearns

Regrets:
  Lea Verou

Chair: astearns

Scribe: fantasai
Scribe's scribe: emeyer

CSS Nesting
===========

Consider using ObservableArray<CSSRule> instead of CSSRuleList
--------------------------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/8350

  TabAtkins: Domenic raised the fact that CSSStyleRule has a new ??
  TabAtkins: it's the weird legacy CSSRuleList
  TabAtkins: which is a weird old DOM interface that pretends to be a
             list, but very awkwardly
  TabAtkins: Suggested to use ObservableArray, which can reproduce
             behavior
  TabAtkins: and we can subclass it stuff
  TabAtkins: I would like to be good, but I would like to be consistent
  TabAtkins: so if we do this, we should do it by creating a subclass
             that adds all the legacy interfaces
  TabAtkins: and do it throughout the CSSOM
  astearns: So on other places where we use CSSRuleList, that would
            result in some extra things that you currently can't do
            with those objects?
  TabAtkins: so we would need tests for all this
  TabAtkins: Yes, all of the array methods, which don't exist on
             CSSRuleList, would start showing up there
  TabAtkins: need tests that we're not doing the weird things

  astearns: [missed]
  fantasai: Are you going to redefine CSS rule list or something else?
  TabAtkins: Redefining CSSRuleLIst
  TabAtkins: I will make it a subclass of ObservableArray
  <fantasai> sgtm

  fremy: Mainly had a question about CSSRuleLIst, right now can you
         modify it?
  fremy: I thought it was a readonly array
  fremy: ObservableArray is read-write
  TabAtkins: That's something that we can define
  TabAtkins: make sure that the readonly bits throw on the setting
             they're deleting
  fremy: Why Observable if it's readonly?
  TabAtkins: ObservableArray is how we should do arrays generally
  TabAtkins: plain array supposed to be static, not invisibly modified
             by the browser
  TabAtkins: ObservableArray allows modification underneath
  fremy: ah, ok
  TabAtkins: Browser doing Observing, which can go both ways

  heycam: This might be first one where API would allow script to
          modify it
  TabAtkins: Possibly? But that would be by luck
  TabAtkins: a script-modifiable ObservableArray is reason we defined
             ObservableArray rather than frozen list
  heycam: Does that have methods that can modify the array?
  TabAtkins: ?? is that array
  TabAtkins: it is an Array exotic object, so looks like an array to
             author script code
  heycam: So you can splice it etc?
  * fantasai is getting confused now, is this read-write or readonly
             now?

  emilio: Plan is to make it readonly?
  TabAtkins: Keep the current readonly-ness
  TabAtkins: except now it will get the array modern methods
  TabAtkins: but it will continue to be readonly
  emilio: So Something.cssRules.push would throw?
  TabAtkins: Yes. WebIDL has you specify the array modification
             behavior using a set/delete algorithm
  TabAtkins: and that gets called by all the mutation methods
             underneath
  TabAtkins: so if you try to modify, it'll throw
  emilio: Then I'm not opposed, but, it feels weird to expose all the
          mutating methods if you can't mutate it?
  emilio: if you feel it's better, sure. Just want to make sure we're
          not making the OM more mutable
  TabAtkins: Don't intend to change mutability, just expose more
             modern interfaces

  fantasai: Why isn't there an equivalent observable array that's
            designed to be read-only?
  TabAtkins: Behavior to make readonly is trivial, just define set/
             delete to throw
  * fantasai doesn't think that answers the question
  TabAtkins: This is an intended use case
  emilio: I think it will confuse authors
  emilio: but we'll see
  emilio: not like you can construct CSSRuleList, so maybe not too
          weird

  plinss: I'm in favor, just two things to confirm
  plinss: We get iterators etc?
  TabAtkins: Yes
  plinss: Perfect
  plinss: My other question, are there other places in the CSSOM where
          we're doing weird array-like things, and if so can we swap
          them all at the same time?
  TabAtkins: I believe that's it for CSSOM, have a pending edit for
             TypedOM
  TabAtkins: which currently uses a better version of fake arrays
  TabAtkins: but I think in CSSOM CSSRuleList is the only actual list
             we have
  TabAtkins: everything else is individual rules
  plinss: Would be good to do a quick pass over everything else, do
          them all
  TabAtkins: Been looking over OM, and everything seems to use
             CSSRuleList, and Declaration doesn't expose anything like
             that
  TabAtkins: theoretically we could also make CSSStyleDeclaration an
             ObservableArray, since it has indexed getting/setting
  TabAtkins: happy to look into it
  plinss: Or making it something maplike or whatever, but in any case
          modernize anything that should be modernize it
  TabAtkins: Should raise as a separate issue
  TabAtkins: only other one that fits in this area, I think
  <fremy> I believe CSSStyleDeclaration should not be made an
          ObservableArray
  <fremy> Otherwise, there can be conflicts between CSS property names
          and Array methods

  matthieudubet: CSSGroupingRule and now CSSStyleRule are really
                 similar implementation-wise
  matthieudubet: insertRule/deleteRule are exactly the same
  matthieudubet: should we expose those as (??)
  matthieudubet: or share code only in the implementation
  TabAtkins: Those all have .cssRules, and then they have legacy
             insertRule/deleteRule
  TabAtkins: If we wanted we could pull those two methods out into a
             mixin, but that wouldn't be a behavior change
  TabAtkins: just better organized specification

  fantasai: I was following up on emilio's concern that we define
            methods that doesn't do anything.
  TabAtkins: Just don't call them
  TabAtkins: Having something be a real array is valuable, and having
             it behave like an array but not have all the methods is
             hard and unnatural in JS
  astearns: Proposed resolution is redefine CSSRuleList as
            ObservableArray, with all of the readonly bits defined
  astearns: particularly carefully since this is the first time we're
            defining such a readonly ObservableArray

  RESOLVED: Redefine CSSRuleList as ObservableArray

  astearns: and also follow-up issue about CSSStyleDeclaration?
  ACTION: TabAtkins to file issue about CSSStyleDeclaration's array
          upgrade

CSSOM for nested media query rules
----------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/7850

  <astearns> https://github.com/w3c/csswg-drafts/issues/7850#issuecomment-1404011020
has the new bits
  TabAtkins: Last discussed in January
  TabAtkins: Basic question was, given that we allow nesting @media
             rule, and then you can put naked declarations inside, how
             do we expose that in the OM?
  TabAtkins: currently CSSMediaRule only exposes child rules
  TabAtkins: The current proposal is if you have naked properties,
             they are effectively wrapped in a nested style rule with
             the & selector
  TabAtkins: and are exposed that way
  TabAtkins: This rule is the first rule in @media's child rules
  TabAtkins: and only exists if it needs to
  TabAtkins: There were two further suggestions
  TabAtkins: One was to add .style accessor that roots to this first
             style rule
  TabAtkins: and/or to change parsing of all nested rules to wrap in &
             {} as well
  TabAtkins: There was mild opposition to both ideas, but ran out of
             time
  TabAtkins: Some concern about adding more rules to large stylesheet
  TabAtkins: suggestion that all nested @rules that accept style rules
             usually, wrap in & {}

  astearns: We could do things later?
  TabAtkins: We couldn't do the second thing, but adding .style is
             still possible in the future

  plinss: Some concern with ability to put raw declarations inside an
          @media rule that's nested
  plinss: because we get yet another situation where you can mix
          declarations and rules, but defaulting differently
  TabAtkins: ...
  plinss: @media contains rules, so it's in rule error recovery
  plinss: if you have stuff in side ...
  TabAtkins: Using same error recovery in all places
  TabAtkins: parser will fail rule parsing if it encounters ; before
             the block
  TabAtkins: today if trying to parse a rule, it will encounter the ;,
             stop there, throw it out, and then start parsing fresh
  TabAtkins: semicolons have never been valid in the front of rules
             before, no expectation that this would break anything
  plinss: If we have declaration top-level with braces, then something
          that follows braces?
  TabAtkins: Generally fine, some restrictions that we want to obey
             for future compatibility concerns, but very minor
  TabAtkins: part of larger issue
  TabAtkins: same effect here as anywhere else
  TabAtkins: won't affect current stuff, because nothing looks like
             that today
  TabAtkins: and in the future, you'll have the same set of
             restrictions everywhere, which are extremely minimal
  TabAtkins: but that's the larger parsing issue, same issue; only
             concern here is whether existing @media would be parsed
             differently, and I think the answer is "no in practice"
  plinss: I accept it's part of the other issue
  plinss: also concerned about older browsers parsing new content
  TabAtkins: If you do nesting in an older browser, things will be
             very screwed up, misparsing is the least of your concerns

  astearns: In the interest of moving forward, perhaps we can resolve
            to wrap things in an implicit & rule if we allow naked
            declarations inside an @media rule
  plinss: I'm ok with that. I'm concerned about requiring &{}
          wrapping, ok if OM is same either way

  RESOLVED: If naked property declarations inside @media become a
            thing, they are wrapped in a & {} rule.

  emilio: Is this anonymous rule well-defined? it's at the beginning?
  TabAtkins: Details in the issue, always at the beginning if it's
             needed
  plinss: If mix of declarations and rules, all the declarations sort
          to the beginning?
  TabAtkins: Yes
  matthieudubet: If they actually write & { ... } explicitly, do we
                 group with that?
  TabAtkins: No
  TabAtkins: If they explicitly write a rule, that's their rule, we
             don't do anything magic with that
  matthieudubet: OK, that's not what Safari Tech Preview is doing
                 right now
  matthieudubet: it tries to show the smallest representation with the
                 same semantics
  matthieudubet: so it removes it
  TabAtkins: This isn't in the spec yet, so it's not tested yet, so
             Safari will discover if it's doing the wrong thing
  emilio: You can't just merge them because the order matters

  <heycam> @media (...) { & { color: red; } color: green; } /* element
           would be red */ ?
  heycam: So just want to clarify that all the bare declarations get
          hoisted to the top of the rule
  heycam: so it might be a little confusing, about the order they'll
          applied
  TabAtkins: It's the same behavior you get in ordinary nested style
             rules, though
  TabAtkins: all your naked declarations are sorted before all of the
             style rules
  fremy: We resolved that we would be consistent, and maybe discuss
         what to do (but nobody filed an issue about that)
  fremy: I think it's weird that they move, but should be consistent
  plinss: If I have a bare red and then two wrapped blue, and then
          bare green, I expect it to be green and it will be blue
  fremy: We discussed in the past, if we agree, we should file an
         issue about that
  TabAtkins: This is a minor issue for compat purposes, so we can
             adjust this
  TabAtkins: I think the answer is, don't put naked things after
             rules; but no reason to ban them
  TabAtkins: either way it's confusing
  TabAtkins: but I don't care which way we go
  TabAtkins: but aside from that, that would be a separate issue, I
             think we're done with this issue
  astearns: Resolution makes us consistent for the moment, but we can
            look at general issue on what to do with general
            declarations

  ACTION: fremy or plinss to file issue about whether naked
          declarations get sorted to the top of the list or not

Nesting conditional rules
-------------------------
  github: https://github.com/w3c/csswg-drafts/issues/7830

  TabAtkins: Implementer in Chrome was wondering if we could punt
             conditional rules to L2, but he ended up implementing and
             it wasn't that bad anyway
  TabAtkins: so proposal is to close this no change

  RESOLVED: Close no change

Feature detection for nesting
-----------------------------
  github: https://github.com/w3c/csswg-drafts/issues/8399

  astearns: Something shipped in Chrome that's not quite what we want,
            but not clear on what we want
  astearns: we should have had a good story before shipping anything
  TabAtkins: I agree that this being parsable before shipping was
             ready was a mistake, but I don't think we can fix
             retroactively
  TabAtkins: Don't think we should expose whether nesting is possible
             or not
  astearns: We shouldn't have feature detection?
  TabAtkins: We shouldn't add anything except selector detection,
             it'll just misfire on some versions of Chrome/Safari

  plinss: Wasn't there discussion of using & in other places?
  TabAtkins: Allowing it elsewhere, yes, but concurrent with Nesting
             being supported
  plinss: Is that guaranteed?
  TabAtkins: In practice yes
  plinss: But it's usable in another feature that's not dependent on
          Nesting
  TabAtkins: Only @scope, but it's also nesting rules ...
  fantasai: That's different from the nesting feature because @scope
            can only contain nesting rules
  TabAtkins: Don't think ti's a problem in practice

  matthieudubet: For feature detection, should we try to give the
                 proper result with a relative selector
  matthieudubet: should @supports be aware of the nesting stack?
  matthieudubet: and always return true/false regardless of nesting
                 stack?
  TabAtkins: The latter. @supports shouldn't be aware of where it is
             in the stylesheet
  <TabAtkins> .foo { @supports selector(&) {...}}
  TabAtkins: that should not give different results at the top level
             vs nested
  <fremy> .foo { @supports selector(+a) {...}}
  matthieudubet: & is allowed both places, but relative selectors are
                 allowed or not depending on whether nested
  TabAtkins: I would prefer we don't make @supports context-sensitive
  TabAtkins: Right now we don't carry context into the querying APIs,
             and you can't express that in JS
  TabAtkins: so as much as possible I'd like to keep those consistent
  matthieudubet: Right now for Safari, it does take context into
                 account
  matthieudubet: so if the selector is not supported *there* it'll
                 return false
  <TabAtkins> CSS.supports()
  TabAtkins: What about CSS.supports()?
  TabAtkins: The JS API can't know the context
  matthieudubet: That's what we do for the at-rules. For JS API, we do
                 the same, so when you write a relative one will
                 always say false
  matthieudubet: because not in a nested context
  TabAtkins: That interpretation is novel, and not expressed in the
             spec right now
  TabAtkins: if we want to do that, can you raise an issue?
  TabAtkins: new issue, please; this is unrelated to the current issue
  astearns: It's better to have specific issues on narrow problems
  astearns: so agree we should have a separate issue on whether
            relative selectors inside @supports are context-sensitive

  plinss: Important that nesting be readily detectable at the top level
  plinss: I have concerns about feature detection of one feature being
          dependent on another feature
  plinss: just because we implemented & and nesting together is cute,
          but not something to rely on
  <emilio> Agreed nesting should def. be detectable in top-level and
           CSS.supports
  fremy: If you want to feature-detect @scope, how do you do it?
  plinss: How do I detect & for @scope?
  TabAtkins: at-supports API doesn't yet allow querying that sort of
             thing
  plinss: We need reliable support detection for nesting, that works
          reliably for @import supports().
  plinss: so & detection is not good enough
  TabAtkins: Currently can only express as selector(&), if you want
             something more specific need a new thing
  plinss: That needs to ship with Nesting

  astearns: Any suggestion of what this might look like?
  plinss: @nest?
  fremy: How about we check whether & is a valid property? That would
         be checking for nesting
  fremy: e.g. @supports (&) { ... }
  <heycam> @supports rule(p { & { } })
  <fremy> @supports (&{})
  <bradk> @supports (nesting) { … }
  TabAtkins: That's not valid property
  TabAtkins: Maybe not that bad given how messy the shipping has been
             with this feature, but in general want to avoid special
             casing
  plinss: We might want a general feature() function for things that
          are hard to feature-detect
  fantasai: I think Francois's suggestion does fit the current syntax
  fantasai: That said, if we do allow that, we'll be allowing any kind
            of selector-based rule that can be nested to be in there
  fantasai: Might be more parsing than we want, but not inconsistent
  TabAtkins: Depends if you think of it as () parses a declaration or
             if () parses "stuff that could go in a declaration block"

  plinss: Would be a problem if we allow selectors, since range of
          selectors is open-ended
  plinss what if we add a div property
  fremy: Same problem we have today already
  fremy: To me, I think it's a nice extension, doesn't require a big
         change
  fremy: not saying we have to do it, it's just an idea
  TabAtkins: Can we do the rest of the design work in the thread? we
             have 9 min on the most important issue

  astearns: Sounds to me that for this issue, we're going to retain
            the bare & supports strategy in the spec, but might also
            add something that is a little more complex or specific?
  TabAtkins: Think so
  astearns: So leave discussion here, don't need a resolution since
            selector(&) already works
  astearns: but will leave this issue open for further discussion of
            supports functionality
  plinss: I believe it's very important that we have a stable and
          reliable mechanism before we ship anything, can we agree on
          that
  TabAtkins: I think it's a good idea, I'm not going to commit to it
  plinss: I think shipping this without reliable feature detection is
          a huge mistake
  <fantasai> +1
  astearns: Agree with plinss
  <emeyer> +1
  <bradk> Me too

  astearns: I think we should have another breakout on Nesting next
            week

Problem with mixing properties and selectors
--------------------------------------------
  github: https://github.com/w3c/csswg-drafts/issues/8249

  astearns: plinss's suggestion is we put the lookahead version into
            the spec
  astearns: and remove references that we had to parts that we had
            based on old parsing mode
  astearns: is that a way forward?
  TabAtkins: That's exactly what I want to do
  astearns: So can we resolve the problem by saying that we'll specify
            the new parsing-enabled version only?
  plinss: I'm uncomfortable with that, depends how we phrase it
  plinss: I'm thrilled that lookahead proved viable. I think this
          should take Option 3 off the table.
  plinss: we should ship with lookahead, or something else entirely
  plinss: I don't care if there's one STP or whatever that shipped
          differently, but what we spec
  TabAtkins: I agree completely
  jensimmons: I don't
  <fremy> fwiw, the lookahead option would satisfy me

  plinss: I still think there are issues with lookahead, but it's far
          better than Option 3
  plinss: I won't formally object provided that we take a step back
          and review all the advantages/disadvantages
  plinss: and reconsider all the options
  plinss: and look at the big picture
  plinss: and whatever we decide as a group, I'll be fine with
  fremy: My concern was that copy and paste would not be viable, but
         with lookahead it is

  jensimmons: I am disappointed that plinss is once again making
              demands that we do what he wants, and assures us that if
              we do he'll be OK
  plinss: I haven't changed my position
  plinss: I'm demanding that we follow the process and make rational
          decisions
  jensimmons: What is happening is that browsers have implemented what
              was specified, and are moving forward despite the
              situation we've found ourselves in in the past several
              months
  jensimmons: and I'm a believer that as we evolve CSS and take an
              idea, work through it, implement and ship it, evolve it,
              continue to add more to it or make it better, and
              implement and ship the newer version
  jensimmons: we have a method to do this, we have levels for
              specifications
  jensimmons: and we keep a trail as we go so browsers can make
              interoperable implementations
  jensimmons: I don't want to obliterate the spec, because it is
              shipping. I would like to write up Level 2
  jensimmons: and browsers can ship that as it's possible to do
  <fremy> -1 because they are not compatible
  <TabAtkins> (we have a working draft https://www.w3.org/TR/css-nesting-1/)
  plinss: We don't have a spec for that, browser shipped outside the
          W3C process
  jensimmons: That's your opinion, don't want to fight about it
  plinss: We had contention and two browsers shipped anyway
  plinss: We have no obligation to spec retroactively

  astearns: We are out of time
  astearns: I would point out that we do have a process for asking the
            WG "are you ready to ship", and that was not followed in
            this case
  astearns: but we'll have to leave this open. We can have another
            breakout next week.
  astearns: Would like people to add comments to the issues so we can
            hash this out and not have new arguments on the call

  [Meeting closed]

+++ Continued IRC conversation +++

  <TabAtkins> We do in fact have an obligation to spec reality. We can
              try to *nudge* reality, but we're not writing fiction.
  <TabAtkins> And we *did* try to follow process, the process was
              dragged out over several browser's explicit requests to
              resolve it.
  <TabAtkins> The process (the WG) failed to work effectively, and was
              routed around.
  <TabAtkins> And now we're dealing with the consequences. Luckily I
              made sure that what we went with was compatible with the
              ideal future, so now moving to the ideal future is easy.
  <plinss> And sometimes the process takes longer than people want,
           but that's still the process, routing around it does not
           supersede the process
  <fremy> To be fair, I will argue the process worked properly here.
          Without objections, we would not have the lookahead version.
          It was deemed impossible. Only when so much pushback
          happened was it properly tested.
  <astearns> +1 fremy
  <fremy> I think the process yielded a better outcome, but
          unfortunately some lost faith before it reached its course
  <fremy> It's understandable, I would have wanted to ship this too if
          I was the PM
  <fremy> No blame handed out
  <fremy> But I think the "work around" was not optimal, here
  <TabAtkins> fremy: The "workaround" was required, because the chairs
              allowed one threatened objection to indefinitely delay
              resolution. That was, itself, a violation of process, as
              Jen pointed out in an earlier call when she *cited* the
              Process and asked for a vote to resolve the logjam, and
              was rejected by the chairs.
  <TabAtkins> More generally, the Process is an way of working toward
              interop, not a suicide pact. We abide by it because it
              generally produces good results, and is a useful
              schelling fence to ground discussions with. But we very
              intentionally do not *require* W3C signoff on shipping
              code in Chrome.
  <fantasai> Dude, not only do you to not require it, you don't even
             *ask* for it, even when it would be useful for the CSSWG
             to have that discussion and even when you would get it.
             It's really obnoxious.
  <fantasai> You ask for TAG signoff, but don't care to ask the CSSWG.
  <fantasai> Even when the CSSWG would actually have more useful input.
  <plinss> and for the record, the TAG didn't sign off on nesting
           either

Received on Thursday, 6 April 2023 17:10:21 UTC