Skip to content

[css-cascade-5] Do conditional rules impact layer order? #6407

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

Closed
mirisuzanne opened this issue Jun 23, 2021 · 12 comments
Closed

[css-cascade-5] Do conditional rules impact layer order? #6407

mirisuzanne opened this issue Jun 23, 2021 · 12 comments

Comments

@mirisuzanne
Copy link
Contributor

In CSS Cascading & Inheritance L5 we define the @layer rule, and the way layers "stack" in priority based on the order they are first encountered. These will stack so the higher numbers override the lower numbers:

@layer one;
@layer two;
@layer three;

In general, layers should interact well with conditional rules. In isolation these two rules should mean the same thing:

@layer one { 
  @media (width > 500px) { /* styles */ }
}

@media (width > 500px) {
  @layer one { /* styles */ }
}

If the media-condition is true, then the styles are applied in the specified layer (one). But it's a bit less clear how the second example (layer inside condition) should impact the order of multiple layers:

@media (width > 500px) {
  @layer one { /* styles */ }
}

@layer two;
@layer three;
@layer one;

Does layer one come first, last, or does it update dynamically based on the evaluation of the condition? I think the two options are roughly:

  1. Layers are always added to the order, no matter how the condition might resolve. It's as though the layer rules "bubble up" to be defined outside the condition, but the styles are still conditional. This matches my instinct, personally.
  2. Layer order is dynamic, based on conditions? It's interesting to consider, but could get pretty surprising…

This question is also relevant to other conditions, such as @supports or @container.

@mirisuzanne
Copy link
Contributor Author

/cc @xiaochengh

@andruud
Copy link
Member

andruud commented Jun 24, 2021

In isolation I like the bubbling suggestion. But I wonder if it's too great an "exception" to how conditionals usually work, and whether adding such special-snowflake behaviors actually end up more surprising. In your latest example, re-ordering based on viewport width just looks like what the author is asking for to me. :-)

There are other options though:

  1. Separate layer ordering declarations from layer usage and make it invalid to order things in conditionals, or (similar):
  2. Make @layer foo {} a parse error inside a conditional unless foo has been (successfully) declared previously.

@xiaochengh
Copy link
Contributor

I think there are two questions here:

  1. Do we want conditional layer reordering?

It seems really broken to me that layers can be conditionally re-ordered. And what's the use case?

  1. If we don't allow it, which syntax do we use?

I prefer the bubbling option, which looks the simplest to me.

@mirisuzanne
Copy link
Contributor Author

I don't think we really can disallow layers inside media (parse error), or even apply the styles without contributing to layer-order. Sites sometimes use an html media attribute on most or all linked stylesheets (eg media="screen" or light/dark mode, etc). We'd be making it nearly impossible to use layers while also using that media attribute. I would find it very confusing if adding media="screen" to a stylesheet totally changed how all my layers work.

@tabatkins also pointed out that once we allow layers inside conditional styles, we can't entirely avoid the dynamic behavior. Browsers often lazy-load stylesheets with an unmatched media attribute. If the media eventually matches, and those styles load late, either approach (always apply, or dynamically apply-on-match) will need to apply those changes once the sheet has loaded. That may be an argument for embracing the dynamic behavior, and making it the spec default.

If we do go that rout, though, we would need a special case for container queries, which do not have any global "matched" state.

@mirisuzanne
Copy link
Contributor Author

To summarize all of the options, and their implications:

  1. Parse error – @layer inside a conditional is ignored, along with all nested styles. I don't think this is viable, since adding media="screen" to a stylesheet could turn the entire file into one large parse error.
  2. Never contribute - @layer works inside conditionals, but without contributing to layer order. Again, I don't think this is viable, for similar reasons. We would also have to determine how layers are ordered if they only appear inside conditions. Would that be a parse error?
  3. Always contribute - When we say @layer statements are ranked in order of first appearance, we mean it, even if that appearance happens inside a conditional. From an author perspective, it is as though the layers "bubble up" to the top level. While this is mostly stable, it is possible for some styles to lazy-load (especially when using unmatched media attributes), so there are cases where a late-loading stylesheet could change the order of layers dynamically.
  4. Fully dynamic - @layer rules inside conditional rules only apply to layer order when the condition is met. This matches the behavior of lazy-loading stylesheets based on the media attribute, but would add a lot more potentially dynamic layer re-ordering based on media changes. Since @container conditions have no global value, but evaluate for individual elements, we would need a special case (option 1 or 2?) for handling layers inside container queries.

@andruud
Copy link
Member

andruud commented Jun 30, 2021

Fully dynamic for @media and @supports + parse error for @container sounds good to me.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed https://github.com/w3c/csswg-drafts/issues/6407, and agreed to the following:

  • RESOLVED: Layer rules respect conditionals, and are ignored in non-global conditionals.
The full IRC log of that discussion <Rossen_> topic: https://github.com//issues/6407
<Rossen_> github: https://github.com//issues/6407
<TabAtkins> miriam: what happens when layers are defined inside of conditionals?
<TabAtkins> miriam: like @media ... { @layer ...; }
<TabAtkins> miriam: Do those layers contribute to layer order, and if so, how?
<TabAtkins> miriam: In the final thread comment i listed the options
<TabAtkins> miriam: First is parse error - don't think that works.
<TabAtkins> miriam: Like what happens when we apply a media to an entire stylesheet? Doesn't seem right to ahve layers disappear.
<TabAtkins> miriam: Second is layers in conditionals don't contribute to the order. This has similar issues - what if a layer *only* appears inside a conditional? Still need some order for them.
<TabAtkins> miriam: So remaining is (3) layers always contribute in order they appear, whether the conditional is matched or not
<TabAtkins> miriam: I think this is my favorite solution, bc it doesn't require special casing
<TabAtkins> miriam: Last solution is to make layer ordering dynamic based on conditionals
<TabAtkins> miriam: In some ways this is true already via (3) with media="" attribute, due to lazy-loading, so you'll get some dynamic behavior anyway
<TabAtkins> miriam: This would just go all the way
<TabAtkins> miriam: It'll need special casing for container queries; they don't have a global match state, they're matched per element. They'd have to fall back to the first or second option there.
<TabAtkins> TabAtkins: I was originally for option 3, but lazy loading made me reconsider, so now I'm strong for option 4 (with ignoring layers in @container rules)
<TabAtkins> TabAtkins: And emilio was also for 4 on Twitter, and it looks like Anders is for 4 from the issue thread
<TabAtkins> miriam: The Twitter thread also voted for 4 by far. (Not always right, but it's useful info about what authors expect.)
<futhark> q+
<TabAtkins> miriam: I think 3 is simpler to udnerstand and teach, but I see the points for 4.
<TabAtkins> miriam: Fine with either way.
<Rossen_> ack futhark
<TabAtkins> futhark: NOt just lazy loading, also inserting stylesheets and rules. You can insert layer rules dynamically, right?
<TabAtkins> miriam: yeah
<TabAtkins> futhark: So I think that leans toward fully dynamic as well, since other things cause similar dynamic results
<TabAtkins> Rossen_: So I'm hearing pretty strong support for 4 among authors and impls. Are you okay with that, Miriam?
<bkardell_> +1
<TabAtkins> miriam: sure
<TabAtkins> Rossen_: Any objections?
<TabAtkins> RESOLVED: Layer rules respect conditionals, and are ignored in non-global conditionals.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed https://github.com/w3c/csswg-drafts/issues/6407.

The full IRC log of that discussion <Rossen_> topic: https://github.com//issues/6407
<TabAtkins> github: https://github.com//issues/6407
<TabAtkins> miriam: So inside of @container, layers can't contribute to order.
<TabAtkins> miriam: Is that a parse error? (layer rules inside of @container is always invalid)
<TabAtkins> miriam: Or is it only an error to *introduce* a layer inside of one, and it's fine to use one that's already defined?
<TabAtkins> futhark: I'll need more time to think
<TabAtkins> TabAtkins: Assuming layered styles are okay inside of container queries generally (I think so, but futhark can correct), then I suggest if a @layer is *introduced* in a @container, it's treated as always being introduced there, regardless of the @container matching or not.
<TabAtkins> futhark: Need some more time to think on the consequences of this
<TabAtkins> miriam: It's basically option 3, but applied only to container queries
<TabAtkins> Rossen_: So doesn't sounds like we have resolution yet, we'll take the rest of this topic to github

@lilles
Copy link
Member

lilles commented Jun 30, 2021

@tabatkins said:

"Assuming layered styles are okay inside of container queries generally (I think so, but futhark can correct), then I suggest if a @layer is introduced in a @container, it's treated as always being introduced there, regardless of the @container matching or not."

I agree.

@mirisuzanne
Copy link
Contributor Author

I agree. I'll begin drafting that language, and we can bring it back to the group for a formal resolution (pending further feedback).

@mirisuzanne
Copy link
Contributor Author

Proposed resolution: If a layer is introduced in a non-global condition like @container, it's added to the layer order as though the condition is true.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Cascade 5, and agreed to the following:

  • RESOLVED: If a layer is introduced in a non-global conditional rule (such as a container query), it always affects the layer order, whether or not that query matches
The full IRC log of that discussion <fantasai> Topic: Cascade 5
<chris> fantasai you will do the transition request?
<fantasai> github: https://github.com//issues/6407
<fantasai> miriam: Question was about defining layers defined inside global conditions like @media
<fantasai> miriam: but open issue about non-global condition like container queries
<florian> s/fantasai you will do the transition request?//
<fantasai> miriam: Thread concluded should always affect layer order
<fantasai> TabAtkins: Looks good
<fantasai> emilio: How do auto-conditionals behave inside container queries?
<fantasai> emilio: Is there a real use case for this?
<fantasai> miriam: If you want some of the things in the container query to be layered or not
<TabAtkins> fantasai: the clarification here is that there's no particular use-case for the layer existing or not conditionally, but there is a use-case for having layered styles in there, so we ahve to define it
<fantasai> emilio: Unfortunate to have to traverse everything
<fantasai> emilio: when building data structure, when finding media/supports query that doesnt' match
<fantasai> emilio: just skip all the rules
<fantasai> emilio: but here you are forced to read all the rules on the page
<fantasai> miriam: you have to do that anyway, because container queries aren't global, you have to read them to understand the page
<fantasai> TabAtkins: I think emilio misunderstood
<fantasai> TabAtkins: in global conditionals, they are conditional
<fantasai> emilio: Oh, I thought we were reverting on that. No, this makes sense.
<fantasai> astearns: Other comments on this?
<fantasai> astearns: If layer is introduced in a container query rule, it always affects layer order, whether or not that query matches anything
<fantasai> miriam: more broadly, any non-global condition
<fantasai> astearns: Any other non-globls?
<fantasai> miriam: Not yet
<fantasai> astearns: Adding that as the reason for this requirement would probably help future spec development, so add editorially
<fantasai> RESOLVED: If a layer is introduced in a non-global conditional rule (such as a container query), it always affects the layer order, whether or not that query matches

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

5 participants