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] Should there be a new syntax for establishing queryable containers? #6174

Closed
mirisuzanne opened this issue Apr 2, 2021 · 11 comments

Comments

@mirisuzanne
Copy link
Contributor

In the current proposal for Container Queries, a container is any element with both layout and size containment. With the addition of 1D size containment (currently only inline), that can include size-containment in the axis being queried. At this point:

.container-2d { contain: layout size; }
.container-inline { contain: layout inline-size; }

If block-only containment is possible, that could expand to:

.container-block { contain: layout block-size; }
.container-width { contain: layout width; }
.container-height { contain: layout height; }

Once a container is established, it acts as a container-query target for descendants. That raises a few related questions:

  1. Are there ever reasons to add layout and size containment, without establishing a new container context for descendant queries? (I don't believe that there is, based on my research so far. Authors generally want to query the closest context possible.)
  2. Are there queryable features that would require a different set of containment values? For example, if we only want to query the value of custom properties, do we really need layout/size containment? (this depends a lot on what features we want to make queryable.)
  3. Can we make it more clear or concise by adding explicit syntax for queries?

New syntax might help address any one or all of those cases, but each use-case might lead to slightly different solutions. This could happen with new values on the contain property, or with a new property (all names to-be-bikeshed):

/* keyword as shortcut for layout/size */
.container-2d { contain: query; }
.container-inline { contain: inline-query; }
.container-block { contain: block-query; }
.container-width { contain: width-query; }
.container-height { contain: height-query; }

/* new property, also triggers appropriate layout/size containment */
.container-2d { container: size; }
.container-inline { container: inline; }
.container-block { container: block; }
.container-width { container: width; }
.container-height { container: height; }

/* queries that don't rely on size containment?? */
.container { container: ???; }
@kizu
Copy link
Member

kizu commented Apr 3, 2021

I would say that I would welcome an explicit separate syntax for defining the containers that enable the queries, but the use-cases for this seem very close to #6176 — basically, I'm afraid of a situation where we add containment on an element for reasons other than querying, but end up changing the context for some of the children. Having these separate (but codependent?) would fix this.

@una
Copy link
Contributor

una commented Apr 28, 2021

Hi all, this is where I think an HTML element could help to differentiate the markup. In many instances with container queries, we need a wrapper element.

<container>
 <div class="child-i-want-to-style">...</div>
</container>

The reason I think introducing a new <container> element via markup could help is to avoid "divitis" and create a bit more clarity for the additional markup that container queries require. It breaks up what would otherwise be:

<div class="container">
  <div class="child-i-want-to-style">...</div>
</div>

And is more declarative in the type of containment, without looking up the CSS. This also prevents the requirement for managing classes like container-inline, container-2d, etc.

Attributes on <container>

We could also use attributes to specify the containment:

<container contain="inline">
 <div class="child-i-want-to-style">...</div>
</container>

Something like <container contain="inline"> or <container inline> would get default CSS values of:

contain: layout inline-size;

<container> by default would have some default styles which could be overridden like other HTML by applying CSS to it.

@eeeps
Copy link
Contributor

eeeps commented May 5, 2021

It might be nice if any shorthand was explicit about the use case that it's solving:

contain: query-target;

I think I like the HTML option in addition to (but not in place of) a way to set query targets in CSS, though I would strongly prefer an attribute that could go on any element. So contain="inline|block" that could go on a <div> or an <article> or a <p> or whatever, but not a whole new <container> element that forces you to lose those other semantics and/or wrap things for styling purposes.

@mirisuzanne
Copy link
Contributor Author

@una / @eeeps I think it the html element/attribute discussion likely deserves a separate issue – if one of you wants to open that? I think it's useful to consider, but doesn't directly impact the CSS syntax questions here.

I like the idea of being explicit (eg query-target) but we need a way to extend that out for different types of query-targets:

  • to query both dimensions of the target: we need to apply layout, style, and 2d size containment
  • to query one dimension: we need to apply layout, style and 1d (inline or block) size containment
  • non-dimensional queries (being discussed in [css-contain-3] What container features can be queried? #5989) might have slightly different requirements (or might not require containment at all, just a syntax for establishing a target that can be queried)

I would hope that any solution we land on can be easily extended, as I expect there will be more interesting container queries down the road that we haven't considered yet.

@bramus
Copy link
Contributor

bramus commented May 6, 2021

Regarding the suggested new property option (i.e. container: size;) it's noted that it “also triggers appropriate layout/size containment”.

Although logical at first sight, this feels a bit weird when compared to how other CSS properties behave. For example, if I set place-items: center; on an element, it doesn't automagically trigger display: grid; along with that. Therefore I also wouldn't expect it to be the case here.

Given that, I'm more leaning towards the new keyword(s) which act as shorthands for the other required values.

@kizu
Copy link
Member

kizu commented May 6, 2021

Ok, but what if the zoom property would enable the containment, this way we could use zoom: 1; to do this…

Being more serious — yep, maybe having this as a sub-property of a contain (that would be available in a shorthand after a slash probably?) is a better idea than a separate property.

@mirisuzanne
Copy link
Contributor Author

So it turns out content-visibility already has the behavior of "turning on" various types of containment behavior from outside the contain property.

It doesn't change the computed value of contain, only the used/applied value – so it's not really one property setting the other, but two properties that can trigger similar behavior. We also do this with things like block formatting context - which can now be set explicitly with contain, but is also required & applied by other properties.

@mirisuzanne
Copy link
Contributor Author

I'm sure we'll bikeshed the details, but here's my initial attempt at a new container property:

main {
  container: inline-size;
}

This property would:

  • Explicitly establish the element as a container
  • Establish the types of queries allowed on the container (e.g. inline-size)
  • Apply the minimum required containment to make those queries possible (e.g. layout, inline-size, and style) without changing the computed value of contain

There are several query/container "types" that we could consider values for:

  • dimensional: size, inline-size (or just inline?), block-size (or just block?)
  • computed values on normal/custom properties: style
  • interaction states: stuck, in-view, etc…

At this point we've mostly focused on dimensional queries, but the others are discussed in #5989. What's most essential here is that the property could be extended as we add new query features. Multiple values could be supplied, and browsers would be expected to determine what containment is required for the given values:

main {
  container: size style state;
}

Bring back named containers?

I think this syntax would also open up a path to bring back named-containers -- similar to the selector argument in David Baron's initial proposal, but more flexible & customizable in the CSS. While I don't think this is needed for most dimensional queries (we almost always want the most immediate dimensions), it becomes more essential when you consider mixing different query types.

In that case, container could become a shorthand property (specific syntax TBD):

main {
  /* container: [ [<custom-ident> /]? <types>+ ] | none; */
  container: layout-area / inline-size style;
}

With two longhand variants:

main {
  /* container-type: <types>+ | none; */
  container-type: inline-size style;

  /* container-name: <custom-ident> | none; */
  container-name:  layout-area;
}

And then queries could include an optional name, before establishing conditions:

/* @container <custom-ident>? <container-query-list> { <stylesheet> } */
@container layout-area (inline-size >= 30em) { /* … */ }

This would resolve in two steps:

  • Find the appropriate container...
    • if no name is specified, use the nearest ancestor container
    • otherwise, filter to the list of ancestor containers with a matching name before selecting the nearest ancestor
  • Resolve the query conditions against the selected container

Considerations

While there might be some downside to triggering contain behavior from outside the contain property, I believe there is already significant precedent for that. On the other hand, attempting to shoe-horn the entire future of Container Queries into the existing contain property would be limiting, and potentially confusing:

  • We might want container values that do not generate any containment behavior
  • There has been significant concern about accidentally creating containers, when you only want to set containment
  • The syntax would get quite cluttered to support both

Next steps

I think there are several questions to answer here:

  • Do we want to add a new property for this purpose?
  • Are we happy with container as a working name for the new property?
  • Are we interested in pursuing named containers?
  • meta: does this all belong in the css-contain spec? Or does some of it belong with css-conditional? Or somewhere else?

(I would save the specific values and other syntax details for separate issues, if we decide to go down this general path)

@bkardell
Copy link
Contributor

I think that I really prefer the idea of "marking" containers specifically with a new property. It makes sense that the 'magic' required to contain for the mainstream traditional ask of "container queries" is also potentially useful for other things (in fact, that is how containment is used in real world/shipping things now), but I really feel like containers are their own thing. Especially if there is any potential that you could have containers be useful for things didn't strictly require containment as we're seeing show up in some other issues.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-contain] Should there be a new syntax for establishing queryable containers?, and agreed to the following:

  • RESOLVED: Container queries are triggered by independent property (name to be bikeshed)
The full IRC log of that discussion <dael> Topic: [css-contain] Should there be a new syntax for establishing queryable containers?
<dael> github: https://github.com//issues/6174
<dael> miriam: In the first prop for container queries and in chrome prototype we've been using establishment of containment.
<dael> miriam: Been concern about that from different angles. Interest in more explicit syntax. Looking at new values for contain which felt cluttered or adding a new property which is what I'm proposing
<bkardell_> miriam: could you summarize what the 'from a lot of angles' concerns about current were?
<dael> miriam: For now calling it container property. Don't know if names are too similar but it's the name of the feature.
<dael> miriam: Idea is this would trigger containment on the backend. I think we have precident for that. This would allow us to flesh out syntax where author only says what they hope to be able to query on a container and then containment happens on the backend. They just say i want to query inline dimension and containment is provided
<dael> miriam: New path for can we have named containers. Can give containers a custom ident. That's a separate issue
<florian> q+
<dael> miriam: Can resolve we like this general direction. Can resolve to move forward with container for now. Also are we interested in pursuing named containers more
<Rossen_> ack fantasai
<dael> fantasai: Question about should it be a keyword in container or separate. Cluttering the syntax might get complicated as you outlined. We can do things like query is a keyword and add other keywords
<dael> fantasai: Question is should they cascade independent or together and that decides if you want separate or same property. Not sure which way, but that's they question you need to ask. Cascade to combine or cascade to override.
<dael> fantasai: It's less about what is the right syntax and more about cascading question
<dael> fantasai: If keyword is query perhaps property should be query since contain and container together might be confusing.
<fremy> Good point. Do we want it to be easy to have `contain:paint` and `contain:container` override each other?
<Rossen_> ack florian
<fantasai> s/right syntax/prettier syntax/
<bkardell_> q+
<dael> florian: From cascading argument I suspect nice to have separate. contain is performance and container queries is not.
<dael> florian: I was wondering, do you expect you will need to set very different types of containment depending on what you need to query about? If yes, argument to sep the two. If regardless of what they want to query it's pretty much set all containments it's less to separate
<dael> miriam: There is talk about types of query that wouldn't require as much or any containment. None is sense of it's outside of element doing the query. That is another reason to add as separate
<Rossen_> ack bkardell_
<dael> bkardell_: I think florian and miriam covered my point. I support htat containers is a separate concept. Currently we don't know everything will require containment as defined in containment.
<dael> bkardell_: Other point is first from florian that containment is used for performance which is a separate concern and don't want to step on one or another
<dael> fremy: I was going to say the same thing
<dael> Rossen_: Any other feedback?
<dael> Rossen_: Prop path...can miriam or fantasai summarize?
<dael> Rossen_: What do we want WG to resolve on?
<dael> fantasai: Prop: Container queries are triggered by independant property
<dael> bkardell_: Still in contain?
<dael> florian: In spec, yes. Mechanics will probably effect used but not computed
<dael> bkardell_: Just meant where does text go
<fantasai> s/computed/computed value of contain property/
<dael> florian: Need to bikeshed spec text.
<bkardell_> interesting!
<dael> fantasai: Prop: Name of property is query rather than container so we don't have contain and container. Either way we go independent prop
<bkardell_> I think miriam also was doing some polling on bikeshedding another name somewhere?
<dael> Rossen_: Prop: Container queries are triggered by independent property (name to be bikeshed)
<dael> RESOLVED: Container queries are triggered by independent property (name to be bikeshed)

@mirisuzanne
Copy link
Contributor Author

Opened issue #6376 for bikeshedding the specific language. Closing this as resolved.

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

7 participants