w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.47k stars 658 forks source link

[css-contain-3] Multiple <container-query>s with multiple containers #6876

Open bramus opened 2 years ago

bramus commented 2 years ago

The spec currently reads (emphasis mine):

Once an eligible query container has been selected for an element, each container feature in the <container-condition> is evaluated against that query container.

Applied to the example below, both conditions will be evaluated against wrapper

.wrapper {
  container-name: wrapper;
}

.wrapper > .child {
  container-name: child;
  --responsive: true;
}

@container wrapper size(inline-size > 30em) and style(--responsive = true) {
  .wrapper > .child {
    /* styles */
  }
}

What I want to have size(inline-size > 30em) be evaluated against wrapper and style(--responsive = true) against child (or any other wrapping container) ?

Would it be feasible to pursue something like the snippet below, where it's allowed to set a <container-name> for each <container-query>?

/* Evaluate size() against wrapper, and evaluate style() against child */
@container wrapper size(inline-size > 30em) and child style(--responsive = true) {
  .child {
    /* styles */
  }
}
bramus commented 2 years ago

(I've already given this some further thought, and have identified that this could have a bigger impact. To not loiter the original post, I'm posting it as a reply)

If this change were to be considered, then why not have the original example @container wrapper size(inline-size > 30em) and style(--responsive = true) also work like @container wrapper size(inline-size > 30em) and child style(--responsive = true), and thus revert that initial quote from the spec?

Would make sense with all elements being style containers by default [^1]. It would make these three examples below — where one is more explicit than the other about which container to target — behave in the same way:

@container size(inline-size > 30em) and style(--responsive = true) { 
  .child {
    /* styles */
  }
}

@container wrapper size(inline-size > 30em) and style(--responsive = true) { 
  .child {
    /* styles */
  }
}

@container wrapper size(inline-size > 30em) and child style(--responsive = true) { 
  .child {
    /* styles */
  }
}

Would also make a lot of sense when nesting @container rules (which isn't specced yet):

@container size(inline-size > 30em) { /* Evaluate size() against nearest size container */
  @container style(--responsive = true) { /* Evaluate style() against nearest style container, i.e. self */
    .child {
      …
    }
  }
}

To have a size() and style() container be evaluated against the same container — which was originally described — the introduction of extra parens could group both conditions:

/* As they are grouped using parens, evaluate both against wrapper */
@container wrapper (size(inline-size > 30em) and style(--responsive = true)) {
  /* styles */
}

In summary, the evaluation would always behave like this:

[^1]: As read in https://github.com/w3c/csswg-drafts/issues/6393#issuecomment-988216116

mirisuzanne commented 2 years ago

First, to address some of the side issues:

But to focus in on the primary questions here:

1. Is it possible for one element to query multiple containers?

[updated to reference current spec language]

While we haven't written nesting in explicitly, I would expect Nested queries allow this already based on the current spec:

Style rules defined on an element inside multiple nested container queries apply when all of the wrapping container queries are true for that element.

Each @container rule would handle container-selection internally, potentially selecting different containers, and the styles would only apply if all container queries resolve true:

@container size-wrapper size(inline-size > 30em) { 
  @container style-wrapper style(--responsive = true) {
    .child { /* styles based on two different containers */ }
  }
}

Which simplifies this issue a bit more, down to just solving:

2. Do we want to allow that in a single @container rule without nesting?

I like the idea. 😁

Maybe we want to spend a little time pushing on it to make sure it really improves readability, since I don't think it adds new functionality. The other question is if it complicates implementation, or if it could be easily added in level 4?

andruud commented 2 years ago

@container wrapper size(inline-size > 30em) and child style(--responsive = true)

Would it then make sense to somehow associate the name/container-selection part with the corresponding condition in a way that's more visually obvious? E.g.

@container wrapper:size(inline-size > 30em) and child:style(--responsive = true) @container wrapper:(size(inline-size > 30em) and style(--responsive = true))

astearns commented 2 years ago

In https://github.com/w3c/csswg-drafts/issues/6644#issuecomment-1034036418 we resolved that a single container query will select a single container to answer all its queries

mirisuzanne commented 2 years ago

I'll leave this issue open for now, since it's a reasonable bit of syntax sugar to consider down the road – but it seems we're not planning to address it in css-contain-3. Maybe I'll label as deferred.