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-contain-3] Define a syntax for state-based container queries #6402

Open
mirisuzanne opened this issue Jun 21, 2021 · 12 comments
Open

[css-contain-3] Define a syntax for state-based container queries #6402

mirisuzanne opened this issue Jun 21, 2021 · 12 comments

Comments

@mirisuzanne
Copy link
Contributor

In the discussion of what container features can be queried, there was interest in queries based on the "current state" of a container – such as whether a position: sticky container is currently "stuck" (displaced from its in-flow position), or whether the box is currently visible on screen.

In the draft of CSS Containment L3 we currently allow a state value for container-type, but different states may require different types of containment (or none at all), so I don't think that single type value will work. We also need to define which states are supported initially, and how these states are queried in the @container rule.

For example, something along the lines of:

header {
  container: is-stuck is-visible / header;
  position: sticky;
  top: 0;
}

@container header (is-stuck) { /* … */ }
@container header (is-visible) { /* … */ }
@fantasai
Copy link
Collaborator

Agenda+ to defer this to L4

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed state-based container queries, and agreed to the following:

  • RESOLVED: Defer state queries to L2
The full IRC log of that discussion <fantasai> Topic: state-based container queries
<fantasai> github: https://github.com//issues/6402
<fantasai> miriam: Resolved recently on style-based queries
<dgrogan> +1 to TYLin, I think this resolution effectively makes transfer size suggestion redundant
<fantasai> miriam: this is about being able to query some state of the container such as being in-view or being stuck (while position: sticky), etc.
<fantasai> miriam: There's also been some discussion of doing this through pseudo classes
<fantasai> miriam: but unlikely we can query the element itself and change its styles
<fantasai> miriam: fantasai and I were thinking to defer this to the next level
<TabAtkins> +1 to deferring while we figure this out
<TabAtkins> nope, fine with the rest
<fantasai> astearns: Any comments/concerns?
<fantasai> Rossen_: What are we losing in L1 if this wasn't well-defined?
<fantasai> miriam: we would be leaving this functionality out entirely. Can't query these aspects of container state
<fantasai> Rossen_: what type of scenarios would be broken or impossible?
<fantasai> miriam: I don't think this was an expected feature, so doubt anyone will miss this
<fantasai> miriam: but things it might add are e.g.
<fantasai> miriam: header that change size when it becomes sticky
<fantasai> miriam: being able to make changes to its stuck state, or maybe trigger animations when it comes into view -- but work happening on that in other places
<fantasai> miriam: those of the main use cases we've thought through so far
<astearns> ack fantasai
<florian> fantasai: the reason I wanted to defer wasn't that we weren't sure
<florian> fantasai: but that a lot of these have complicated interactions
<florian> fantasai: in the sticky case for example, if we have a way to select when something is stuck
<florian> fantasai: then we can change not only that size, but the layout of the page too
<florian> fantasai: finding a way to prevent that isn't the way it's working right now
<florian> fantasai: these are important use cases to work on, but the answers are very complicated
<miriam> +1
<argyle> related https://github.com//issues/5979
<fantasai> s/we can change/it changes/
<florian> fantasai: so I don't think it makes sense to deal with them in the same level as other things that are much more solid
<fantasai> Rossen_: Unsure about cost-benefit tradeoff here
<fantasai> Rossen_: don't want to be broken by default
<fantasai> fantasai: This isn't undefinin anything, this is just deciding not to add a feature
<fantasai> fantasai: not going to break anything
<argyle> q+
<fantasai> astearns: My thought is that if we are defining all of the things that this feature would depend on without thinking about the implications of this feature, we might paint ourselves into a corner
<fantasai> astearns: only reason to keep in L1 is to make sure L1 is defined compatibly
<fantasai> astearns: but I'm not concerned about that dead-end
<fantasai> Rossen_: That's my concern also, so want to keep it in L1 so it nags us
<astearns> ack argyle
<fantasai> argyle: It's a nice to have
<fantasai> argyle: and also introduces a lot of very complex problems to solve
<fantasai> argyle: Shared a GH issue of how to get around the looping issue for :stuck , e.g.
<fantasai> argyle: it's complicated
<fantasai> argyle: but things folks want to do are in L1 already
<fantasai> argyle: there are nice queries like overscroll or whatever, that we could have, and maybe we could allude to the possibility of doing that
<fantasai> argyle: maybe we could do one or two, not all of them
<TabAtkins> I'm sorry, but I am still utterly confused by what Rossen is referring to by "breakage". This is a proposal for brand new functionality; deferring it, by definition, can't break anything. (The use-case just remains unsolved for now, but it's been in that state for years already with no progress.)
<fantasai> argyle: punt additional use cases and additional state queries to L2
<TabAtkins> no need to q+ me, that's it
<TabAtkins> ack
<TabAtkins> ack TabAtkins
<fantasai> argyle: I'm excited about the ideas, but ok to defer
<fantasai> astearns: I just want us to keep this thing in mind and not block off development
<fantasai> astearns: I think it's fine to defer to L2, anyone object?
<gtalbot> [crikets chirping sound]
<fantasai> RESOLVED: Defer state queries to L2

@matthew-dean
Copy link

@mirisuzanne

I don't know how to formulate this idea, but it would be nice to query state / behavior from things like Grid / Flexbox, particularly around things like:

  • Is this flexbox wrapped?
  • Which "row" of a flexbox am I in?
  • Which row or column of a Grid am I in?

The reason why I'm thinking about this is that there are tricks in flex-basis that people are using right now that create kind of an equivalent of container queries. The problem with something like flex-basis and flex-wrap is that you have a layout behavior applied at an unknown point / state. So you can't exactly use a container query to "capture" when the state / layout of that box / container changes.

So, like, there's a Switcher layout in the Every Layout library that, when content size is below a certain width, using flex-basis magic, it will change a 3-column layout to a single column layout w/ 3 items. It would be nice to query when this happens, because the Flexbox doesn't "know" when that flex layout happens, and we're now in a single column.

Because it's not based on a single property, and not necessarily a single "width", I really don't know how you would query it? But I just thought I'd put it out there. Here's a Codepen showing a Switcher with neither container nor media queries. https://codepen.io/matthewdean/pen/bGaKwRx

@matthew-dean
Copy link

matthew-dean commented Apr 9, 2022

I wonder.... if there's something like a syntax missing like a way to "push" state in CSS based on something... happening? I think it should be more like a way to push a state like :active or :focused, such that the syntax is more like:

header:sticky {
  background: red;
}

If you think about it, :active or :focused are types of state for an element, and "querying them" (selecting them) doesn't require a container query. If there was a way to define / push state from HTML / CSS, you could also have something like :state(is-sticky, is-visible) and expand it to include existing states like :state(focused).

@matthew-dean
Copy link

matthew-dean commented Apr 9, 2022

Imagine, for example, an accordion. Say it could do this.

<div class="accordion">
  This is some content
  <button type="button" class="button">This is an accordion opener</button>
  <div class="hidden">
   This is hidden content.
  </div>
</div>

<style>
  .accordion {
     /** Or @state accordion(open, closed)? Allows multiple state vars and values? */
     @state open;
   }
   .button:pressed {
     /** Or toggle: accordion? */
     toggle: state;
   }
   .hidden {
     display: none;
   }
   .accordion:state(open) .hidden {
     display: block;
   }
</style>

Some kind of state system would prevent having to do radio button hacks with sibling combinator selectors to try to change a state of another element based on input of an initial element.

@mirisuzanne
Copy link
Contributor Author

@matthew-dean in terms of syntax and 'pushing state' to CSS, you might be interested in #6991 and the linked spec/explainer for our CSS Toggles proposal. I think it lines up pretty well with what you're suggesting in the last two comments.

The idea of querying where an element lives in a grid/flex layout is interesting here, especially since it would require the limitation of a container. What I mean is: if we allowed an element to query it's own position in a layout, and then change the value of say grid-area based on that, we end up in a potentially recursive loop. But if we only allow you to change descendant styles based on the position of an ancestor in the grid, we avoid that loop. So it does seem like an interesting use-case that might require something container-query-like.

@matthew-dean
Copy link

matthew-dean commented Apr 12, 2022

@mirisuzanne

@matthew-dean in terms of syntax and 'pushing state' to CSS, you might be interested in #6991 and the linked spec/explainer for our CSS Toggles proposal. I think it lines up pretty well with what you're suggesting in the last two comments.

Oh my god y'all are geniuses. A little different syntax, but yes!!

But if we only allow you to change descendant styles based on the position of an ancestor in the grid, we avoid that loop. So it does seem like an interesting use-case that might require something container-query-like.

As to the other thing, yeah, I can't quite think of how this would work syntactically, but it feels like there are... I dunno, behaviors? States? Of CSS elements? That are defined / designed to be triggered by other properties.

I just thought of a good allegory, which is a pseudo-element like ::first-line. So it's a selector that is applied once other selectors (and layout) have been applied. So, similarly, I'm thinking of selectors that allow you to select things based on the resulting layout of flexbox / grid. (Not that it's as easy as ::first-line.... although... it would be funny / amazing, if ::first-line could be applied to flex / grid rows, or similar concepts like ::first-row, ::nth-row(), ::last-row, ::last-column etc ..... i.e. with old table markup, you could select :nth-child(), but there's no way to select implicit rows / columns / etc yet)

See: this Stack Overflow question in which one of the answers to alternating color rows in CSS grid is basically to hack it by using a repeating gradient: https://stackoverflow.com/questions/58251569/coloring-every-other-row-using-css-grid

@lilles
Copy link
Member

lilles commented Aug 21, 2023

I have started an explainer for state queries here: https://lilles.github.io/explainers/state_container_queries.html

@lilles
Copy link
Member

lilles commented Aug 24, 2023

There is now also:

@lilles
Copy link
Member

lilles commented Nov 1, 2023

The TAG review is closed.

I would like to start working on a specification for scroll-based state queries. The states to be added at this point is:

  • Stuck: query whether a sticky positioned container is stuck (offset applied) in a given direction
  • Snapped: query whether a scroll-snap-aligned element is snapped to its scroll snap container in a given direction
  • Overflowing: query whether a scrollable container has scrollable overflow in a given direction

Proposed resolutions:

  1. Add the following to css-contain-4:

    • sticky, snap, and overflow as new container-type values that can be combined with existing container types
    • A state() function, similar to the style(), to @container to query these states
  2. Use the same modifications to the HTML event loop as for scroll-driven animations to avoid layout cycles

Details for the proposed syntax can be found in the explainer, but is up for bikeshedding

Details and rationale for using the HTML event loop modifications can also be found in the explainer.

@woody-li
Copy link

woody-li commented Nov 7, 2023

Overflowing: query whether a scrollable container has scrollable overflow in a given direction

Is it available for detecting text overflow (ellipsis) state like #4123 ?

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-contain-3] Define a syntax for state-based container queries, and agreed to the following:

  • RESOLVED: create ED of css-contain-4 with all editors of css-contain-3 as a diff spec
  • RESOLVED: add scroll-state() to css-contain-4
  • RESOLVED: move explainer into the csswg-drafts repo
The full IRC log of that discussion <bramus> futhark: State Contqiner Queries allow you to do container queries based on scroll position. TAG was positive about it. previously this was resolved to delay to L2 of the spec (contain 4) and I started on the prototype with sticky pos and am now asking if we can start working out a spec for a new function state in the @container rule and introduce 3 new SQ types (sticky, snap, and overflow)
<TabAtkins> +1 obvs, this would be great
<bramus> … second thing is that i am not sure to resolve on, but what i investigated is that it requires a modifcaition to the the HTML event loop similar to scroll driven animations.
<bramus> … eg for sticky it needs a snapshot
<bramus> astearns: q on the second bit: exactly the same changes?
<bramus> futhark: yes, exactly the same thing – at the same time
<miriam> q+
<bramus> astearns: any questions?
<astearns> ack miriam
<emilio> q+
<bramus> miriam: what do the container type values do on the container? do they apply containment or just mark it as available?
<bramus> futhark: just available, but might want to impose some containment restrictions. you can have same issue with hover here (flipping between states)
<bramus> … needs to investigaged. Do we impose the restrictions or do authors need to do it themselves?
<bramus> astearns: Is it OK if we start out with no extra containmenbt effects and then figure it out?
<bramus> miriam: I think we want to resolve that before shipping, but now not opposed
<astearns> ack emilio
<bramus> emilio: state is also used for custom state psuedo, so might be confusing
<bramus> futhark: yeah, syntax is up for bikeshedding
<fantasai> maybe call it scroll() or scroll-state() or something?
<bramus> emilio: other thing: you mention HTML event loop level snapshotting such as SDA. For animaitions you can get away with that, but I wonder for the rest, as you can query it outside of anmiations. I wonder if you need to ??? a bit more.
<bramus> futhark: not sure what you mean by that … it is not possible to call getboudningclientrect in between these two ???
<bramus> emilio: yeah, but I expect these queries to work outside of the rendering loop
<bramus> … what happens if I run random JS task, does it need to eavluatie these query when not having performed the snapshotting yet?
<flackr> qq+
<bramus> futhark: I would assume that you need to do that snapshot as well when doing that. seeing similartyt with size container queries affecting gCS.
<bramus> emilio: fine if this is TBD
<bramus> futhark: needs to be investigated
<astearns> ack flackr
<Zakim> flackr, you wanted to react to emilio
<bramus> flackr: FWIW you can do same thing with scroll animations. gBCR is affected by ?? and you can call outside of lifecycle update
<astearns> s/??/animations/
<bramus> … when you call it before the first rendering update, the timeline is inactive bc it is not snapshotted yet
<bramus> … when applied to state queries, they could be not active until first rendering update
<bramus> futhark: makes sense to me but … q is: is this important use case or does it need to be defined/specced?
<emilio> q+
<bramus> flackr: its not great for the author bc they get incorrect values when called before 1st rendering update
<astearns> ack emilio
<bramus> emilio: my q was more in line to make sure this is defined
<bramus> … authors are much more used to animations not returning super precise states but i think this would be kind of a first
<bramus> … that may be fine. no strong opinion.
<bramus> flackr: hover is a bit similar I think, but expectation is that hover doesnt get updated until you move th emouse
<bramus> emilio: but it is different … this is not like a pseudo class that does/doesnt apply … not sure, maybe hover analogy is OK?
<bramus> astearns: I think we can resolve on adding the values and function and then try to define the interaction (or open a new issue for that)
<bramus> futhark: yes, but css-contain-4 doesnt exist yet
<bramus> astearns: yes, that would be created
<bramus> fantasai: we should add resolution for that
<bramus> astearns: PROPOSED RESOLUTION: create ED of css-contain-4 with all editors of css-contain-3 as a diff spec
<bramus> RESOLVED: create ED of css-contain-4 with all editors of css-contain-3 as a diff spec
<bramus> astearns: PROPOSED RESOLUTION: add sticky, snap, and overflow as new container type values
<bramus> RESVOLED: add sticky, snap, and overflow as new container type values
<bramus> astearns: state as conflict … scroll or scroll-state were suggested … can add scroll-state to start with?
<bramus> futhark: yeah, no strong opinion about the name
<bramus> astearns: PROPOSED RESOLUTION:add scroll-state() to css-contain-4
<bramus> … objections?
<bramus> RESOLVED: add scroll-state() to css-contain-4
<bramus> astearns: other things about this?
<bramus> futhark: No
<emilio> q+
<bramus> astearns: thanks for the epxlainer and tag review
<dbaron> should the explainer move into the csswg-drafts repo?
<astearns> ack emilio
<bramus> emilio: last minute q: do we need 3 different container types here?
<bramus> futhark: I think it makes sense given the current prototytping. only thing is i fyou want to select different ones you need to use names
<bramus> emilio: so we need 1 or 3?
<bramus> futhark: 1 makes sense
<miriam> +1 to a single container type, if it works technically
<bramus> astearns: no resolution on that just yet, lets wait on prototype
<bramus> astearns: PROPOSED RESOLUTION: move explainer into the csswg-drafts repo
<bramus> RESOLVED: move explainer into the csswg-drafts repo
<dbaron> (in contain-4)

aarongable pushed a commit to chromium/chromium that referenced this issue Nov 30, 2023
Per resolution in [1]. Also use a single scroll-state container type
instead of separate types for sticky and snap, including a new runtime
enabled feature, implied by any enabled query feature, to check when
recognizing the container type and parsing the scroll-state() function.

[1] w3c/csswg-drafts#6402 (comment)

Bug: 1445189, 1475231
Change-Id: I9acaf7570e9ee98157e31d0ff238bd0cd585dfad
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5075421
Commit-Queue: Rune Lillesveen <futhark@chromium.org>
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1231311}
lilles pushed a commit to lilles/csswg-drafts that referenced this issue Jan 26, 2024
Resolved to move explainer from lilles.github.io in issue w3c#6402
mirisuzanne pushed a commit that referenced this issue Jan 26, 2024
#6402 (#9865)

* [css-contain-4] Move state queries explainer #6402

Resolved to move explainer from lilles.github.io in issue #6402

* state() -> scroll-state()

---------

Co-authored-by: Rune Lillesveen <futhark@chromium.org>
lilles pushed a commit to lilles/csswg-drafts that referenced this issue Aug 20, 2024
Per resolution in [1], add scroll-state() as a query function to query
sticky, snap, and overflow scroll states with a new container-type for
scroll-state queries.

[1] w3c#6402 (comment)
lilles pushed a commit to lilles/csswg-drafts that referenced this issue Aug 28, 2024
Per resolution in [1], add scroll-state() as a query function to query
sticky, snap, and overflow scroll states with a new container-type for
scroll-state queries.

[1] w3c#6402 (comment)
lilles added a commit that referenced this issue Sep 4, 2024
Per resolution in [1], add scroll-state() as a query function to query
sticky, snap, and overflow scroll states with a new container-type for
scroll-state queries.

[1] #6402 (comment)
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

6 participants