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] Revisit decision to make style the default container-type #7066

Closed
mirisuzanne opened this issue Feb 16, 2022 · 28 comments
Closed

Comments

@mirisuzanne
Copy link
Contributor

mirisuzanne commented Feb 16, 2022

In #6393 (comment) we resolved that:

Boxes default to style containment

@una reopened that discussion in #6393 (comment), and it was briefly discussed again in #6644 (comment) without any definitive conclusion.

It seemed like a good idea for this discussion to have its own issue.

The primary concerns on each side are:

  • Keeping the style default makes one container type inconsistent with all other types. And while it helps with queries on inherited properties, it makes container-name much more important for style queries on non-inherited properties (like background-color).
  • Removing the style default makes it much harder to query inherited properties, which should almost always resolve against the direct parent. Without the default value, authors are likely to add the style container-type to all elements with the universal selector, which is less performant.

Related, I'm curious about the details of what it means to have style as a default. Do we mean…

  • …that style is the initial value of the property, and any other value overrides that behavior? In this case, authors would have to write e.g. container-type: size style in order to keep the default intact while adding other container types. That doesn't seem ideal.
  • …that all elements are style containers, no matter what value is applied to the property? In this case, we might not need an explicit style value? Or a variant might be that the default can be removed with none and re-applied with style?
@fantasai
Copy link
Collaborator

fantasai commented Feb 16, 2022

I think the reasonable answer is “that all elements are style containers, no matter what value is applied to the property”, otherwise authors will break things accidentally as they adopt size queries throughout their pages. That said, we could reasonably add a value that removes the ability to query at all, as long as it's an explicit disabling value, like no-style or something. (none might also work, for disabling all types simultaneously.)

@astearns
Copy link
Member

I’d like to see more discussion here before we spend time on the call again. @una do you have any thoughts on this since the last time?

@emilio
Copy link
Collaborator

emilio commented Mar 30, 2022

I'm a bit concerned about making style the initial container type. It can have somewhat annoying performance implications in the sense that now even non-inherited style changes can affect styles in the elements' subtree.

It's not impossible to optimize some of the cases, but it seems unfortunate to add overhead by default.

@mirisuzanne
Copy link
Contributor Author

@emilio It seems likely to me that if we don't make style the default, authors are likely to add it as a global setting anyway - similar to the way they currently change box-sizing globally. Without that, it is very difficult to use style-queries with inherited properties in any practical way. That seems like an even worse option for performance in my mind?

@emilio
Copy link
Collaborator

emilio commented Mar 30, 2022

Maybe? Not sure about that, I'm concerned about is the defaults... If you opt into everything being a container, then sure, so be it, but you've done it explicitly. But making the default behavior more expensive seems a bit unfortunate.

@anttijk
Copy link

anttijk commented Apr 7, 2022

I'm strongly opposed to style (or any) containers being the default for the reasons mentioned my Emilio.

@matthew-dean
Copy link

matthew-dean commented May 5, 2022

@mirisuzanne

It seems likely to me that if we don't make style the default, authors are likely to add it as a global setting anyway - similar to the way they currently change box-sizing globally.

I was going to ask this in a different thread but I found this here. It seems to me that the way the spec is currently defined, it will soon become "best practice" to do something like:

html {
  box-sizing: border-box;
}
*, *::before, *::after {
  box-sizing: inherit;
  container-type: style size;
}

That is, I can't think of a scenario where I wouldn't want the ability to drop in a container query for size or style whereever I please. (Because, for example, in component-based design and development, a component can sometimes be added anywhere, so it needs all of its parents to be queryable containers if the component has component queries.) But, that said, I don't really understand the performance implications of setting this globally but not querying the style.

@mirisuzanne
Copy link
Contributor Author

@matthew-dean I strongly agree that it will become best-practice to add style container-type globally (tho the current spec does that by default). However, authors will need to be much more careful about applying size containers, because the added size containment removes all intrinsic sizing of children from the container's intrinsic size. Every element would layout as though empty if you applied that globally. Since a lot of CSS layout relies on containers using the intrinsic sizing of their child elements, that's a pretty dangerous tradeoff that authors will need to consider case-by-case.

@matthew-dean
Copy link

matthew-dean commented May 6, 2022

@mirisuzanne

However, authors will need to be much more careful about applying size containers, because the added size containment removes all intrinsic sizing of children from the container's intrinsic size. Every element would layout as though empty if you applied that globally. Since a lot of CSS layout relies on containers using the intrinsic sizing of their child elements, that's a pretty dangerous tradeoff that authors will need to consider case-by-case.

Oh, interesting. Is there an explainer for this that demonstrates the visual effect of applying different container-type properties?

I don't know if this is useful, regarding applying size which effectively removes style, Less has a syntax for "adding values" to existing list values, as well as a keyword like all which applies all items from a possible list. The former (a CSS native way of adding to an inherited list value) may be out of scope for this feature, but the latter (a single keyword representing both) could be a possibility.

@mirisuzanne
Copy link
Contributor Author

mirisuzanne commented May 23, 2022

Oh, interesting. Is there an explainer for this that demonstrates the visual effect of applying different container-type properties?

@matthew-dean I think this behavior is described in several places, but I don't know if any of those descriptions really 'demonstrate the visual effect' in a simple & clear author-centered way. That would be a good example to have somewhere. We could consider adding a note/example to the spec, but it will be even more helpful to call out in articles about the feature.

Less has a syntax for "adding values" to existing list values, as well as a keyword like all which applies all items from a possible list.

There are several other open issues about that exact idea, and I think we do need something like that. But I don't see any reason to define it in a way that is specific to container queries. It's something we would want to define generically for all list values, and should be handled elsewhere.


@astearns I think it would make sense to bring this issue back to the group? With several implementors arguing against the current behavior, and several browsers preparing to ship the feature, it seems important to discuss the tradeoff they bring up. I think this issue needs to be resolved before any version of the feature can be shipped, since it impacts the default value of the property?

  • on the one hand, in order for style queries to be useful on inherited properties, authors will want style containers set globally. If that is an author setting, they will also need to be careful not to override it when adding size containers. Since size CQs are likely to launch before style CQs, this will create some unexpected difficulties for authors once both are supported. It's not as simple as adding the global style value, it will also have to be added to every instance of container-type that might accidentally override that global setting. If we go that rout, we need to clarify that the default style-container behavior is not overridden by author values (as described by fantasai).
  • on the other hand, it sounds like this desired behavior may cause performance issues for browser engines.

I think we've made the right choice about how the syntax should ideally work for authors. But, of course, performance is also important to authors. It's not clear to me how those concerns should be balanced, or how bad the performance impacts would be, but I'd like to resolve that question one way or the other so that we don't accidentally paint ourselves into a corner.

In either case, this issue needs clarification in the spec.

@lilles
Copy link
Member

lilles commented May 25, 2022

I think the current spec with initial value being style is the least attractive here because:

  • Authors will accidentally stop style queries from working with container-type: inline-size as @fantasai points out
  • It means shipping size queries separately will require a different initial value than what's given per spec

Having all elements being style containers by default will require authors to be a bit careful with selectors inside style queries. Queries like this (selectors matching a whole lot of elements) could easily cause implementations to take a performance hit:

@container style(--foo: bar) {
  :first-child { color: green }
}

@fantasai
Copy link
Collaborator

fantasai commented Jun 1, 2022

+1 to @lilles, if style is the default we need to make specifying other keywords not override it (same as adding additional counter-resets doesn't drop the list-item increment).

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-contain-3] Revisit decision to make style the default container-type.

The full IRC log of that discussion <fantasai> Topic: [css-contain-3] Revisit decision to make style the default container-type
<fantasai> github: https://github.com//issues/7066
<fantasai> miriam: We've discussed this a few times, but the resolution we took last time need some clarification either way
<fantasai> miriam: We resolved last time we talk to make every element a style container by default
<fantasai> miriam: On the one hand, in this thread, it seems we feel confident that's a good choice in terms of author expectations in terms of style queries
<fantasai> miriam: really helps for inherited properties, if you can assume that you always get the value from the parent
<fantasai> miriam: if we stick with that direction, need to clarify what it means for being default
<fantasai> miriam: does that mean style is the default, but if set other type, would drop style type?
<fantasai> miriam: more likely, would mean every container is a style container, always true of all elements don't have a value for it
<fantasai> miriam: So if we want to stick with that resolution, need to clarify that this is how it works
<fantasai> miriam: On the other hand, all three browser engines have commented that this would be a performance hit
<fantasai> miriam: I'm not sure how we want to weigh those two things
<fantasai> miriam: allowing people to set them individually let's people control performance
<fantasai> miriam: but if set style globally to get the behavior we want, then would have to juggle carefully your values because then it would get overridden when you try to set up other types of containers
<fantasai> miriam: so we have a potential perf issue vs author usability
<futhark> q+
<fantasai> Rossen_: Want to know if implementers would clarify the exact perf implications
<Rossen_> ack futhark
<fantasai> futhark: I'm not sure we can say it's a perf issue in general, but in certain cases can get into one
<fantasai> futhark: if you look at example I gave, where you have a universal first-child rule that queries a custom property.. if you don't use container names
<fantasai> futhark: you could query a custom property that only makes sense for certain parents in the document
<fantasai> futhark: but in order to figure out that this custom property can cause invalidation of children, would have a lot of overhead
<fantasai> emilio: Would make style queries evaluate against all elements by default, which is not amazingn
<Rossen_> ack fantasai
<emilio> fantasai: I think the authoring usability problems are actually pretty severe
<emilio> ... it's not too bad to require somebody who wants to use style queries to set this extra rule on all elements
<emilio> ... but the fact that it becomes nearly impossible for the author to then juggle to different values
<emilio> ... so that when they want to set a size container they also need to set style size instead of just style
<emilio> ... that's very tricky and easy to get wrong
<emilio> ... if you have multiple sets of libraries it's very easy to get conflicts
<emilio> ... only way to resolve that problem would be to split the container property into multiple boolean properties
<emilio> ... in order to allow authors to turn them on and off independently
<emilio> ... if we want to avoid making this the default we need to turn them into longhands
<emilio> ... and I suspect most libraries would set style containment as a convenience to the author
<emilio> ... and we're going to have to make these optimizations anyways
<emilio> ... so if we end up having to make these optimizations I'd say we'd rather do this
<emilio> q+
<Rossen_> ack emilio
<fantasai> s/do this/make it the default/
<fantasai> emilio: the problem with making style containment the default, that wouldn't solve the problem with conflicts right?
<fantasai> fantasai: if we make it the default, it would always be a style container regardless of other containment set on it
<fantasai> fantasai: same way list-item is always incremented, unless you explicitly say not to
<fantasai> miriam: that's the clarification we needed if we went in that direction
<jensimmons_> q+
<fantasai> emilio: I don't quite get why style queries are useful
<fantasai> emilio: it seems that regardless of what path we take, the initial value for container type should be 'none' and when we get to style queries, just make every element magically a style query container
<fantasai> emilio: does that sound like a reasonable description of what we're proposing?
<fantasai> fantasai: I think so yes
<fantasai> jensimmons_: I'm still confused about the author experience here
<fantasai> jensimmons_: I think we'll teach everyone to use size queries for the next 2 years, and in that teaching they will be taught that you have to define your container
<fantasai> jensimmons_: your query will be against that container
<fantasai> jensimmons_: when style queries come along, I think authors will expect it to work the same way
<fantasai> jensimmons_: I think they will define a container on the root, or on the main div, or a side element, or whatever
<fantasai> jensimmons_: rather than * { everything }
<fantasai> jensimmons_: I agree that there's a problem with size queries and style queries both being set on the same element and accidentally overriding each other, and we can address that problem
<Rossen_> ack jensimmons_
<fantasai> jensimmons_: that's a flaw, maybe we can address it
<fantasai> jensimmons_: they're going to be designing components and dropping randomly in the page
<fantasai> jensimmons_: there's 2 components, sans-serif and then serif typography stuff, and want to query which one is set and query on that
<fantasai> jensimmons_: but this particular component is going in different places, so font-family is inherited through the tree
<fantasai> jensimmons_: so idk maybe answering question as I talk
<fantasai> jensimmons_: but maybe Miriam you can explain why we want to get away from the idea of defining container
<fantasai> miriam: For non-inherited properties it would work fine to set the container and query it, but for inherited properties you always need to check the parent
<fantasai> miriam: otherwise not getting an accurate idea
<fantasai> miriam: you're generally always going to want to know the closest answer
<fantasai> miriam: and it becomes very fragile if you have to set that explicitly
<emilio> q+
<fantasai> miriam: every time I want to check whether font is italic, I have to make sure the parent has the right style container type before I can find out whether I'm inheriting italics
<fantasai> miriam: and I think that's one of the key use cases
<fantasai> miriam: if the parent's italic, make me normal, if the parent is normal make me italic
<fantasai> miriam: this use case is only possible if we can assume querying parent
<fantasai> miriam: for non-inherited properties, we can always set a name
<fantasai> miriam: and we've gone out of our way to encourage naming containers, both with size queries and style queries
<fantasai> miriam: so that will transfer, there will be differences in these two in how they're used, but if querying something specific you'll give a name
<emilio> q- later
<Rossen_> ack fantasai
<emilio> fantasai: The case where you want to have 2 different styles, you don't actually want to be querying the font-family property
<emilio> ... you likely want to query a custom property
<emilio> ... and you just want to make a custom property that represents your style
<emilio> ... you'll want to track those through custom properties and the style query would let you query what kind of thing you're inside
<emilio> ... and querying always the parent makes sense even if you want to switch (e.g., if you want to switch your color-scheme)
<emilio> ... so I think you want to track that info through a custom property rather than attaching everything to a container
<fantasai> dbaron: Wanted to comment on a use case Miriam raised wrt font-style italicy toggling
<emilio> dbaron: Just wanted to comment on one of the use cases miriam mentioned (toggling between italic/normal)
<fantasai> dbaron: I think using style queries for that feels like a very heavyweight mechanism for solving that problem
<fantasai> dbaron: we had the cycle()/toggle() proposal for that
<fantasai> dbaron: I think a mechanism like that would be more efficient way to address that sort of use case, whereas doing that with style queries, you're using something that's got much bigger perf implications
<fantasai> dbaron: because it's a mechanism that can query any property and apply the result to any other property
<Rossen_> ack fantasai
<bkardell_> I was going to queue to say similar to dbaron - for that specific case at least
<Rossen_> ack dbaron
<Rossen_> ack emilio
<fantasai> emilio: Wanted to make a comment similar to dbaron's, other proposals that may address many of these use cases
<emilio> like `if(<foo>, <bar>, <baz>)
<fantasai> jensimmons_: From what fantasai described, using custom properties and querying them
<fantasai> jensimmons_: put the word style aside, it becomes a way to define variables and query which one is being used right now
<fantasai> jensimmons_: which CSS doesn't have right now
<fantasai> jensimmons_: when people get their heads around that, they might not care about styles, they might just need variable queries
<fantasai> jensimmons_: and that's what they'll start using it for
<fantasai> miriam: large overlap with leaverou's higher-level custom properties proposal, in terms of use cases
<fantasai> miriam: setting properties that you can query and use them in selectors, and make larger changes based on the value of a property
<fantasai> fantasai: There was some issue Oriol raised against toggle(), we decided didn't matter because moving to style queries, but if not need to dig up that issue and see if solvable
<SebastianZartner> If it's mainly about querying custom properties, why not restrict to them for now to do style queries?
<fantasai> fantasai: Regardless of this, do we need to split contain property into longhands per containment type?
<fantasai> fantasai: to avoid conflicts
<fantasai> jensimmons_: If we land somehwere that every element is style container always, then no problem, but otherwise we need to solve the problem
<fantasai> jensimmons_: if someone wants to set up a size query ends up accidentally turning off a style query, that's accidental result
<fantasai> jensimmons_: consider working across teams, across time
<fantasai> fantasai: lots of room for error if we don't split
<fantasai> jensimmons_: especially since the whole point is to allow ppl to create [missed]
<fantasai> jensimmons_: don't know what kind of collisions you'll create
<fantasai> Rossen_: doesn't sound like we're approaching consensus, if anything sounds like we're expanding the problem space of the issue and underlying features
<fantasai> Rossen_: If this was in times when we have more regular F2Fs, I'd say let's do a breakout and come back with proposed changes and move on from there
<fantasai> Rossen_: so perhaps that's what we need to do, do a breakout similar to scroll animations and hash it out
<fantasai> Rossen_: sounds like topic is expanding rather than converging
<fantasai> miriam: I think it's possible that emilio's suggestion would allow browsers to release without a problem
<fantasai> miriam: initial value is 'none', and if make style containers the default, not doing with an initial value of style would do it more globally
<fantasai> miriam: so that might be a resolution that gets us able to release size queries without solving this
<emilio> fantasai: I have a different idea
<emilio> ... that'd solve style queries, but not other types of containment in the future
<emilio> ... cause we want to also allow for other containment types in the future
<emilio> ... we'd need to release a longhand
<emilio> ... my concern is that grouping these into this one property causes issues in the future
<emilio> ... I think that's something we are going to need to explore before we ship
<emilio> ... because if we ever add another type of containment that isn't size containment...
<emilio> jensimmons_: maybe we don't even need to make them a shorthand
<emilio> ... whatever gets decided I'd argue for folks to decide soon
<emilio> ... because Safari 16 is going to ship container queries
<emilio> Rossen_: I don't think we'd like to suggest to punt on this for weeks or months
<emilio> ... still not hearing good consensus
<emilio> ... do we want to try to resolve on anything today?
<emilio> ... or do a breakout session next week or so?
<emilio> fantasai: I'd say we discuss and explore the longhands approach and come back next week
<emilio> Rossen_: I think there are a couple of other issues in the same space that deserve focus time
<emilio> ... happy to help organize something
<emilio> ... if that moves the ball forward quicker
<emilio> emilio: It seems there's agreement on `style` not being a value on `container-type`
<emilio> ... regardless of whether we split `container-type` into longhands or not
<emilio> fantasai: I wouldn't be happy to resolve without an alternative
<emilio> Rossen_: let's take it back to the issue
<emilio> ... and bring it back next week. Happy to prioritize if there's progress / something we can resolve on

@andruud
Copy link
Member

andruud commented Jun 10, 2022

@fantasai How about we make "additive cascade" happen, and live with container-type issues until then? :P

Maybe there's a nice way to split container-type into multiple longhands, but if there isn't, it would be sad to add a more general solution later that would make those longhands look stupid in retrospect.

@lilles
Copy link
Member

lilles commented Jun 13, 2022

It's not clear to me how container-type should be split into different longhands.

If we split into separate longhands, we would still have the issue with the container shorthand?

Say we have a new 'state' container type and split into size-container and state-container properties.

Setting both name and inline-size via the shorthand will reset the state-container:

#container {
  state-container: foo
}

#container {
  container: name / inline-size
}

If we add:

size-container: (none | inline-size | size)

Do we want to have a short-hand for setting size-container + container-name?

That is:

size-container-type: (none | inline-size | size)
size-container: name / size-container-type

Also, would that mean that we would not longer need the full container shorthand. Still an issue with a shorthand with:

size-container: size-name / inline-size
state-container: state-name / foo

if the first value is container-name

@andruud
Copy link
Member

andruud commented Jun 14, 2022

Since multiple vendors seem to think it's a little late to get creative here, I propose that we do this:

  • container-type:none is the initial value, and actually means "none", without implying a style container.
  • Authors who prefer style-by-default must then do * { container-type:style; }.
  • Authors who want to add size-container to something must then remember to do div { container-type:size style; } to preserve the style container type. For now.
  • Additive cascade improves the situation in the future.

I understand that it's not ideal, but I don't understand why it's necessary to do an emergency hack for this particular case when a) other parts of the CSS has had the same problem all the time (contain, animations, backgrounds, etc), and b) the work-around for the near/medium future is basically "remember to add 'style' to container-type".

Yes, other kinds of containers are vaguely planned, and if that somehow makes the situation unacceptable, then we can focus on doing additive cascade first.

@anttijk
Copy link

anttijk commented Jun 14, 2022

How about simply making inline-size and size also be style containers (they already imply style containment)? Then you have a clean one dimensional hierarchy of progressively stronger containers: none, style, inline-size and size (with none being the default). Everything should be perfectly forward compatible when shipping without style queries.

@dbaron
Copy link
Member

dbaron commented Jun 14, 2022

Does that mean that when engines start shipping style containment, there will be a performance penalty for existing uses of size containment that don't need style containment?

@mirisuzanne
Copy link
Contributor Author

How about simply making inline-size and size also be style containers (they already imply style containment)?

This seems like a one-off solution that would protect only the style container-type from overrides. The concern that @fantasai has raised is that we may want a more generic solution for any number of future container types that may overlap and conflict in different ways. I get that concern.

But I also agree with @andruud's assertion that these problems already exist many other places in CSS. To that point, container-name should also ideally be 'additive' – allowing authors to establish different names in different places and for different reasons, without those names overriding each other. That problem is not easily solved by breaking out more longhands. A container can have multiple size names, just as likely as it has names relating to different container types. I don't think it makes sense to have style-names and size-names and state-names, etc. So it makes sense to me that a 'generic' solution should be even more generic (we need additive cascade), rather than looking for a solution that is generic only to container-types.

But generic additive cascade is not an easy problem to solve. So, short-term, do the longhands help us get there?

the longhand approach

Say browsers launch with two longhand properties, and plans for a third (if not more):

/* launching soon… */
size-container: [none | size | inline-size];
container-name: [none | <custom-ident>+];

/* someday later… */
style-container: [none | style];

If we stop there, it works. When style-container lands, authors can add it as desired, without causing any size-container conflicts. But as soon as we add a shorthand, we're back where we started – a single property that overrides future properties:

/* launching soon… */
container: <container-name> / <size-container>?;

/* someday later… */
container: <container-name> / <size-container>? <style-container>?;

In the immediate, authors will set container: name / inline-size, seeing it as a helpful shortcut. But as soon as we add style containers, that new longhand is already in conflict with any use of the existing shorthand. Authors are overriding a value that didn't even exist when they initially wrote the code.

Maybe that's what @fantasai had in mind – longhands, without any shorthand? I think it works, and sidesteps @lilles concerns about merging multiple shorthands. This seems like a viable path to me (tho I still want additive cascade for container-names).

on the utility of 'style queries' generally

Along the way, several people have questioned if 'style queries' are even useful, especially if we have individual inline functions like toggle()/cycle() or even if(). I'm working on a larger summary of the use-cases here, and will post that soon. But the quick summary is, functions like toggle() only work when:

  1. you want to set a single property
  2. based on the parent value of only that same property

That works (and is even elegant) if you want to simply cycle a font-style between normal and italic, based on the parent font-style. But it falls apart as soon as you get any more complex about the relationships:

  1. adding multiple conditions
  2. styling a different property than you query
  3. styling multiple properties based on a shared condition

All of those become more essential for use-cases discussed in #5624, but are even required for this simple case (based on a demo from @una elsewhere):

@container style(font-style: italic) {
  em, i, q {
    background: lightpink;
  }
}

@SebastianZ
Copy link
Contributor

It's a bit late here, so maybe the idea is not completely thought through. Though what about basing querying solely on container-name for now and deferring container-type and everything about style containers?

That would mean, it's required to specify a name for the container to establish it as a query container. The queries then also require to specify the name additionally to the (size) container query.

This should allow implementations to ship without issues. And for a later version of the specification we can then come back and resolve the issues around style containers and make the name optional again.

Sebastian

@mirisuzanne
Copy link
Contributor Author

@SebastianZ Container type is essential for size containers, even setting aside style for now, because it applies the necessary containment (layout, size/inline-size, style), which can be pretty invasive. What containment is needed depends on the specifics of the type, which we can't infer from a name alone.

@lilles
Copy link
Member

lilles commented Jun 15, 2022

If we have a solution for applying container-type from different shorthand-declarations, but not a solution to apply different container-names to the same element from different declarations, is that really useful if authors will typically use container-names in their queries?

@andruud
Copy link
Member

andruud commented Jun 15, 2022

Looks like an inconsistent mess to me.

@SebastianZ
Copy link
Contributor

@SebastianZ Container type is essential for size containers, even setting aside style for now, because it applies the necessary containment (layout, size/inline-size, style), which can be pretty invasive. What containment is needed depends on the specifics of the type, which we can't infer from a name alone.

So it probably was too late yesterday.😆 The idea would only work if we made size containers the default.

Just to summarize how container queries should work as proposed for my (and hopefully other people's) understanding:

Size containers queries: closest ancestor query container matching the queried container features and optional name
Style containers queries:

  • non-inherited properties: closest ancestor query container matching the queried container features and optional name
  • inherited properties: parent element (<= That's the main issue.)

Sebastian

@mirisuzanne
Copy link
Contributor Author

Sorry for another long comment, but I feel like there are again several issues getting confused in the thread - and I'd like to provide some context for how they pull apart, and how they relate. (along with the resolution that I would like to see here)

The idea would only work if we made size containers the default.

Even different size containers rely on different containment (1d or 2d), so there's still no obvious 'default' that we could apply, even with size-alone. There's no way to remove container-type without severely limiting the feature.

Just to summarize how container queries should work as proposed…

All queries use the same logic: querying the nearest ancestor container that is able to reflect the requested features, optionally with a given name.

In most cases, for both size and style, it would be ideal to query the direct parent by default - because the baseline purpose of container queries is to have the most immediate information available.

That's not viable with size queries, because they require invasive containment in order to 'reflect the requested features' – so authors need to carefully select where that containment is applied. With style queries, any element would be 'able to reflect' the query without any intervention, because no containment is required. The same seems likely for the potential 'state' queries that have been discussed so far.

In cases where authors don't just want the nearest ancestor, but want a specific container, they can use a container-name to look farther up the tree. That will be useful across all query types, and is especially a good idea when querying non-inherited properties.

All of this has lead to several distinct questions that are getting mixed together in this thread:

Are style queries even useful?

I'm confident that they solve a problem that has been raised in various places, and I will continue to make the case for them. But either way, my syntax proposal for what to launch now is the same (see below).

Should every element be a 'style container' by default, since no containment is needed?

We initially said 'yes', because this entire feature is designed around authors getting the most immediate available information by default. For usability of the feature, this is the right way to go. Container-name is a better solution than container-type for filtering the list of containers when necessary from an author perspective. It is also likely to make sense down the road for other hypothetical query-types that don't rely on specialized containment, since it seems like the ancestor-descendant requirement is enough to protect most query-types from looping.

Are there performance issues that should make us reconsider that?

The answer depends on both the implementation approach, and the way authors write their queries. Those potential performance issues only apply to the resolution of style queries, they are not a general performance penalty for all sites across the board.

Container queries involve two levels of element 'filtering' - one to find the 'containers' elements that will be queried, and the other to find the selector 'target' elements impacted by the query. Currently, the Gecko and Chromium implementations filter selector targets first, and then use that information to narrow the search for viable containers (which must be an ancestor of the target). The Webkit implementation takes the reverse approach - first filtering viable containers, and then selector-matching only within their descendant trees. As with the internals of selector-matching, the more narrowly targeted the first step, the better the performance. If selector-matching narrows the list farther, then it ought to go first, and vice-versa.

If all elements are style containers (either by default, or through a global declaration), then a style query without a container-name is very broadly targeting all elements as potential containers. That will impact the performance of all container-first filtering algorithms. The first step has basically no filtering impact. For selector-first algorithm, the impact is relative to the specificity of selectors involved. In either case, it is possible for authors to cause performance issues through a combination of broad selectors inside broadly-targeted queries. The concern is that having more containers on the page makes more queries 'broadly-answerable'.

Since authors are likely to apply this global rule if we don't, it seems essential that we optimize for it, no matter how we conclude this issue. It's also possible that selector-first filtering will have some advantages here. In the meantime, authors can avoid those performance concerns by using container-names to narrow the container list, or keep selectors more narrowly targeted to avoid broadly-applied queries.

However, it's still not clear to me how much of a performance slow-down we're talking about. While the * selector is less performant than an #id, that hasn't been enough of a difference to impact most developers choice of selectors.

Can we help authors avoid some container declarations overriding others?

With both container-types and container-names, it's likely that authors will want to apply different values in different places – and ideally would be able to merge those declarations, rather than one overriding another. That's an issue that has come up with many other CSS properties, and is the driving concern behind the idea of 'additive cascade'.

In this case, we could consider breaking out individual longhand properties for different categories of container-type (size, style, etc) which would allow those types to be set in parallel. But:

  • That doesn't help with conflicts inside a given category (size vs inline-size)
  • It only works if authors entirely avoid the shorthand, which would reset all longhand values anyway
  • The conflict is even more likely with container-names, which cannot be broken into shorthands

I don't think the benefits here are worth the effort. I would rather see us work on a general solution to the problem of additive cascade.

My proposal

These are all good concerns to raise, and I'm glad to be walking through them in some detail. I find it very hard to weigh the performance concerns in relation to author usability - since it involves a number of factors that change over time. Clearly, implementors have a better sense of that than I do. But at this point I still feel that we had the right proposal here initially.

I would like to resolve that:

  • The initial value of container-type is none.
  • All elements are style containers, no matter what container-type value is applied.
  • Browsers should feel free to ship size queries as they are implemented, and ship style queries later.

In the meantime, I'll work on providing more detailed use-cases for style queries, so that the reason for implementing that feature is clear. Even if I fail at that, this resolution on the initial value of container-type allows us to ship the best syntax for size queries now. And if anyone wants to work on a proposal for additive cascade, I would love to help push that forward.

@matthew-dean
Copy link

@mirisuzanne

if anyone wants to work on a proposal for additive cascade, I would love to help push that forward.

* cracks knuckles *

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Revisit decision to make style the default container type, and agreed to the following:

  • RESOLVED: Initial value is `none`
  • RESOLVED: All elements are style containers by default.
The full IRC log of that discussion <TabAtkins> Topic: Revisit decision to make style the default container type
<Rossen_> q?
<TabAtkins> miriam: There's been more discussion. I left a summary, well, longer than that, at the end fo the thread. No responses since.
<TabAtkins> miriam: So same question as last time - last time we talked about it it split into several questions.
<fantasai> https://github.com//issues/7066#issuecomment-1158184820
<TabAtkins> miriam: 1) Do we need style queries? I think we do, I argued for it.
<TabAtkins> miriam: 2) If we have them, should every container be a style container by default. I think answer is yes for authors, question is perf.
<TabAtkins> miriam: In convo with emilio it seems the perf issues are less (maybe not none) if the impl first matches selectors then looks for containers
<chris> rrsagent, draft minutes
<RRSAgent> I have made the request to generate https://www.w3.org/2022/06/22-css-minutes.html chris
<TabAtkins> miriam: If you're going the other way and matching containers first, and everything's a container, you don't get much filtering.
<TabAtkins> miriam: Those perf issues are only for people using broad container queries (not using name, etc) and broad selectors. Multiplying those together means lots of searching
<TabAtkins> miriam: I don't know how bad that perf hit would be, so hard for me to judge on that.
<TabAtkins> miriam: Proposal moving forward is [whoops, missed]
<TabAtkins> miriam: If we start now with an initial value of none, browsers can release size queries, and I think that's the right syntax
<TabAtkins> miriam: Other question: people will set contianer types in various places, also names
<TabAtkins> miriam: Suggestion was to set type in another longhand. But that doesn't work for names.
<TabAtkins> miriam: I think the general solution is an additive cascade. No specific solution, need general solution here.
<Rossen_> q?
<TabAtkins> Rossen_: Any further comments?
<futhark> q+
<TabAtkins> futhark: I'm supportive, I said so on her writeup
<TabAtkins> futhark: Positive to the proposed resolutions
<Rossen_> ack futhark
<astearns> read the comment and support the suggested resolution
<TabAtkins> futhark: Important thing now for chrome and safari is to end up with th einitial value of `none`, will let us ship CQs without having to worry about this idea
<TabAtkins> s/this idea/whether everything's a style container/
<TabAtkins> futhark: We're exploring style queries; right now it doesn't sound that bad to have them as default
<TabAtkins> fantasai: I'm in favor of miriam's points
<TabAtkins> Rossen_: Miriam could you summarize?
<TabAtkins> miriam: First resolution, initial value is `none`
<chrishtr> +1 to Miriam's proposed resolution.
<TabAtkins> Rossen_: Objections?
<SebastianZartner> +1 from me, too
<TabAtkins> RESOLVED: Initial value is `none`
<TabAtkins> miriam: Since style queries are in the spec, probably need a resolution for every element being a style container by default. We'll spec that out and adjust as needed as impls start showing up.
<TabAtkins> fantasai: Resolution si that every element *is* a style container, regardless of `container-type`.
<TabAtkins> emilio: Still skeptical about this.
<TabAtkins> emilio: Gecko's CQs are like Blink's. It's a little more annoying to have every element be a style container.
<TabAtkins> fantasai: Argument is a lot of people will do that anyway because it's useful to query, so you'll take that hit on a lot of pages anyway.
<TabAtkins> fantasai: That's our expectation.
<TabAtkins> emilio: I don't know if my expectation matches, but you know more about CSS authors. Okay with that for now, guess I don't object.
<TabAtkins> RESOLVED: All elements are style containers by default.
<SebastianZartner> Congrats Miriam!
<fantasai> Side question, should 'none' be 'normal' now since everything's a style container?
<bramus> Nice!

@bramus
Copy link
Contributor

bramus commented Jul 7, 2022

For completeness, linking to #1594 here. It’s the issue talking about “Additive Cascade”, a concept which was mentioned a lot here.

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