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] Reference named containers for cq units #7858

Open
una opened this issue Oct 7, 2022 · 25 comments
Open

[css-contain-3] Reference named containers for cq units #7858

una opened this issue Oct 7, 2022 · 25 comments

Comments

@una
Copy link
Contributor

una commented Oct 7, 2022

In the [contain-level-3] spec it is possible to name containers, referencing them in @container. It is also possible to use container query units. However, it seems like there is a gap (I might be missing it in the spec) for how to reference a named container when using cq units.

An author might want to specify the container they are referencing when using the cq units (rather than defaulting to the nearest container). Using container-name wouldn't work, since it would set the name. Would it be possible to add a "container-reference"-type-property (name TBD) that can be accessed within an CSS declaration?

I.e. for illustration:

.meta p {
  container-reference: card;
  font-size: clamp(1rem, 10cqi, 2rem);
}
@LeaVerou
Copy link
Member

That doesn't seem ideal, because then you cannot combine measures from multiple containers.

What if instead of cq* units we got a function that would accept an optional container name? E.g. container([w | h | min | max] [of [<custom-ident> | closest] ]?)

Then one could use custom units to have a --cq* unit that does whatever they want.

@nmn
Copy link

nmn commented Oct 11, 2022

What if instead of cq* units we got a function that would accept an optional container name? E.g. container([w | h | min | max] [of [ | closest] ]?)

This feels like the right solution to me, but I'm not sure about the exact syntax proposed. Perhaps we can use container-reference as function name to combine both your ideas?

.meta p {
  font-size: clamp(1rem, container-reference(10cqi, card), 2rem);
}

One benefit I see of doing this is that it extends the container units that have already been introduced and other than learning about a single new function, introduces no new syntax.

I'm not completely sure about the function name though. Some other ideas:

  • for-container-named()
  • for-container()
  • in-container-named()
  • from-container()
  • container()

Further, I'm not sure this syntax could fly, but this could work very well as well:

.meta p {
  /* `of` or `from` or `in` */
  font-size: clamp(1rem, 10cqi of card, 2rem); 
  font-size: clamp(1rem, calc(1rem + (3cqi of card)), 2rem);
}

@Loirooriol
Copy link
Contributor

Or add functional versions of the units: cqw(<container-name>), cqh(<container-name>), etc.

@nmn
Copy link

nmn commented Oct 15, 2022

Or add functional versions of the units: cqw(<container-name>), cqh(<container-name>), etc.

This was my initial thought too, but it feels like it might not be valid syntax? Do we have function calls as units in CSS. Or, is it a proposal?

if the syntax 10cqw(<container-name>) is valid, then that would be the absolute best option!

@Loirooriol
Copy link
Contributor

It wouldn't be a unit, it would be a function returning a length that could be used wherever a length is expected, just like calc(10px * 2).

We already have 10--cqw meaning calc(10 * var(--cqw)), so 10cqw() is not unreasonable. But not strictly necessary, since you could use things like calc(10 * cqw(card)) or clamp(1rem, 10 * cqi(card), 2rem).

@frivoal frivoal changed the title [css-contain] Reference named containers for cq units [css-contain-3] Reference named containers for cq units Oct 24, 2022
@mirisuzanne
Copy link
Contributor

Agenda+ to see if we can resolve on this. I agree that the ideal is to have:

  • Function names matching the unit names we already have, eg cq*()
  • The functions can be used in calc() and return the value of a single unit, eg calc(10 * cqw(card))
  • From there, it's a bonus if we can also use the functions directly as units, eg 10cqw(card)

Meanwhile, the plain units without a function argument continue to refer to the nearest available container.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-contain-3] Reference named containers for cq units.

The full IRC log of that discussion <dael> miriam: The request is with ontainer quereis want to query a specific container. Can do with full syntax but not w.ith units. Units give nearest container with right dimenions. It's a good default
<dael> miriam: Nice if you can get the width, height, etc from a specific container
<dael> miriam: Prop is starting ith cq functions that match unitis cqw, cqh, etc. Function takes 1 arg which is name of container. Returns the value of @Unit. You can use that in calc, multiply by something, and query a specific container.
<dael> miriam: Bonus request is do we allow function appended to a value is same way as with custom units. Nice to do with functions. Functions are powerfut even without
<dael> TabAtkins: New functional unit is brand new syntax. Not a problem, but just for conservitiveness I think we want to lean existing pattern. I would think takes cq-length and contextually interprets based on cintainer name as other argument
<dael> miriam: Suggestion a function that's both multiplier and name?
<TabAtkins> container-reference(10cqi, card)
<dael> TabAtkins: Same as nmn (sp?)
<dael> TabAtkins: THis function ^ Relative to name from second argument
<ntim> q+
<dael> miriam: Could work. As soon as looking at container-reference with 2 arg does ti have broader uses? container-reference(2em, card) I would use
<dael> TabAtkins: We could define tightly and extend. If we go for more than 1 dimension, aka a calc of stuff, I suppose works. It's more work impl-wise
<dael> fantasai: All of this is longer to type than calc, right? calc with a bunch of functions would be easier
<miriam> calc(10 * cqw(card))
<miriam> container-reference(10cqi, card)
<dael> TabAtkins: What I desc is shorter than doing same thing with calc. If it's conainer reference that takes name and returns the unit length that's longer
<astearns> ack ntim
<fantasai> how is that strictly longer
<dael> ntim: Would it allow querying the units for containers outside of the container chain?
<dael> ntim: And any concerns if it is allowed?
<dael> miriam: The way I was thinking of it is resolves same as container queries so has to be ancestor
<dael> astearns: Nearest ancestor whose name matches
<dael> astearns: One minute left. Hearing this is good to have but a bit of quibbling over syntax.
<dael> miriam: Can take it back to the issue
<TabAtkins> hm, i guess functions with the name of the cq* unit lets you collapse things down to a pretty short thing.
<dael> astearns: Yep. Let's take it back to the issue and go over syntax, but let's try and take this up. Seems like it will be very useful

@astearns astearns removed the Agenda+ label Jan 5, 2023
@Loirooriol
Copy link
Contributor

TabAtkins: New functional unit is brand new syntax. Not a problem, but just for conservitiveness I think we want to lean existing pattern. I would think takes cq-length and contextually interprets based on cintainer name as other argument

I strongly disagree with container-reference(10cqi, card). Precisely, making lengths context-depend would be the complete opposite of an existing pattern. I think it will be very confusing and problematic, and I don't see any need to do that.

Like, if container-reference(10cqi, card) is valid, is container-reference(calc(10cqi), card) also valid? And container-reference(calc(10cqi + 0px), card)? Does it accept any <length>? What does it do for other units?

I'm fine with container-reference(10, cqi, card) or container-reference(10 cqi, card) or calc(10 * container-reference(cqi, card)). But passing a length seems to open an unnecessary can of worms. My preference is for 10cqi(card) or calc(10 * cqi(card)).

@LeaVerou
Copy link
Member

LeaVerou commented Jan 5, 2023

Agreed with @Loirooriol, more specifically on this:

But passing a length seems to open an unnecessary can of worms. My preference is for 10cqi(card) or calc(10 * cqi(card)).

@romainmenke
Copy link
Member

10cqi(card) is maybe also problematic, I don't like that this is a dimension token with a simple block attached to it.

calc(10 * cqi(card)) seems much more inline with what already exists in CSS today.

@LeaVerou
Copy link
Member

LeaVerou commented Jan 5, 2023

10cqi(card) is maybe also problematic, I don't like that this is a dimension token with a simple block attached to it.

It's not. Functional units would expand the definition of <dimension-token> from <number-token> <ident-token> to <number> [ <ident-token> | <function-token> ] (@tabatkins feel free to correct me if I'm mistaken).

@mirisuzanne
Copy link
Contributor

Another approach would be cqi(10, card) - which could be used inside or outside of calc. I think that avoids new patterns entirely, since it's just a set of new match functions. Used with custom units, you could do something like:

html {
  --card-i: cqi(1, card);
  --card-min: cqmin(1, card);
}

div {
  padding: 10--card-min 10--card-i;
}

I still like the functional unit approach if possible, though.

@Loirooriol
Copy link
Contributor

Loirooriol commented Jan 5, 2023

@LeaVerou Note that a <dimension-token> is a single token, not <number-token> <ident-token>.
For example, width: 100px has a <dimension-token> and works, width: 10/**/px has a <number-token> <ident-token> and doesn't work.

So Romain is right that with the current syntax, 10cqi(card) would be a <dimension-token> followed by a ()-block. I guess we could leave this as 2 tokens, which would have some oddities like accepting 10cqi/**/(card) as valid even if that wouldn't be valid with a function token, or change the syntax to treat it as a single token.

Or just go with the simpler calc(10 * cqi(card)). I also like the cqi(10, card) from the previous comment.

@mirisuzanne
Copy link
Contributor

Might be better as cqi(<name> [, <multiplier>]) to allow without the multiplier, or even a syntax that allows a name or multiplier or both. Without a name it would be similar to current cq units (maybe not needed), without a multiplier it would return a single unit (a more useful shorthand). Since idents and numbers have distinct syntax, they could be space-separated and optional without relying on order.

@LeaVerou
Copy link
Member

LeaVerou commented Jan 6, 2023

@LeaVerou Note that a <dimension-token> is a single token, not <number-token> <ident-token>. For example, width: 100px has a <dimension-token> and works, width: 10/**/px has a <number-token> <ident-token> and doesn't work.

So Romain is right that with the current syntax, 10cqi(card) would be a <dimension-token> followed by a ()-block. I guess we could leave this as 2 tokens, which would have some oddities like accepting 10cqi/**/(card) as valid even if that wouldn't be valid with a function token, or change the syntax to treat it as a single token.

I was referring to how <dimension-token> is built up by smaller tokens, see the railroad diagrams here: https://drafts.csswg.org/css-syntax/#ref-for-typedef-dimension-token%E2%91%A2
I imagine this would change to include a <function-token> branch.
The alternative, as you point out, has several issues.

Or just go with the simpler calc(10 * cqi(card)). I also like the cqi(10, card) from the previous comment.

Might be better as cqi(<name> [, <multiplier>]) to allow without the multiplier, or even a syntax that allows a name or multiplier or both. Without a name it would be similar to current cq units (maybe not needed), without a multiplier it would return a single unit (a more useful shorthand). Since idents and numbers have distinct syntax, they could be space-separated and optional without relying on order.

Is cqi(card, 10) just syntactic sugar for calc(10 * cqi(card))? If so, my preference would be to keep the cqi() definition short and not add syntactic sugar for simple math. If there's a huge need for it, we can add it later (with the syntax Miriam proposes).

@mirisuzanne
Copy link
Contributor

Yes, that's syntax sugar - and not as nice a sugar as 10cqi(card). So I agree it may be good to start with the functions, and then consider some form of syntax sugar as needed.

@LeaVerou
Copy link
Member

LeaVerou commented Jan 6, 2023

Another issue with adding that syntactic sugar is that it means we can never add a second <number> argument that does something else.
I just realized that if we could have had functional units, they could have been a more elegant solution for viewport units, rather than the combinatorial explosion of viewport units we now have.

@mirisuzanne
Copy link
Contributor

Agenda+ to see if we can resolve on adding cq*(<container-name>) math functions. Down the road, there are several possible paths to provide syntax sugar around that – via custom units or functional units or additional arguments – but this would provide the basic functionality without introducing larger language features.

@mirisuzanne
Copy link
Contributor

I suppose that was the original proposal. There is also the option of a more verbose (but more powerful) container(<unit> [, <container-name>]) – which adjusts @tabatkins proposal to fit @Loirooriol's critique. That would only require a single function, and could also be used to access other relative units computed against the container.

h2 {
  font-size: calc(container(em, my-container) * 1 + container(cqi, my-container) * 2);
}

(I have often wanted the ability to reference the 'em' value on elements other than the root…)

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-contain-3] Reference named containers for cq units, and agreed to the following:

  • RESOLVED: add a function for every container query unit that allow to reference a named container
The full IRC log of that discussion <emeyer> miriam: There are two function proposal on this
<emeyer> …There’s concern about using actual lengths in these functions
<emeyer> …Idea is to be able to query for a specific container
<emeyer> …Could query for container 10cqi and a container name
<emeyer> …Idea 1: a new function for each container unit
<emeyer> …Woulc take the argument of a container name
<emeyer> …Idea 2: Have a general container unit reference function
<emeyer> …Something like `container-unit(<unit>,<container-name>)`
<emeyer> …Could use this in calc() to do whatever math is needed
<emeyer> …This is a little bit bulky that would help authors clean this up a bit, but it’s a good start
<emeyer> …I like the second idea; probably needs some bikeshedding on the name
<TabAtkins> happy with either, honestly
<emeyer> astearns: Anyone with opinions or dislikes?
<TabAtkins> latter is verbose but the functionality makes sense
<emeyer> emilio: There are units that don’t make sense in a container function, right?
<emeyer> miriam: Yeah
<emeyer> fantasai: The only relevant units are font-relative and container-relative
<emeyer> emilio: I’m not particularly opposed, but some of these seem like they could be handled differently
<emeyer> …This feels a bit weird
<TabAtkins> q+
<emeyer> …I have a slight preference for the first option, but not strong
<astearns> ack fantasai
<astearns> ack TabAtkins
<emeyer> fantasai: I like that the first idea is easier to type and is a straightforward extension of existing syntax
<emeyer> TabAtkins: I agree with emilio that the general function is a little funky
<emeyer> …We could make a cqem unit and corresponding function, so I think I’d be happier with dedicated functions
<emilio> +1
<emeyer> …Plus a non-binding intent to always have a function that goes with any new CQ unit
<emeyer> astearns: I’m a little excited about the more vague function — why just units, why not custom properties?
<emeyer> TabAtkins: That wouldn’t be the container unit function which needs to be a math function
<astearns> ack fantasai
<emeyer> fantasai: I think we should start where we can make things so we treat this like a unit
<emeyer> miriam: The custom units proposal would let you wire that uop
<emeyer> s/uop/up/
<emeyer> astearns: Sound like we’re converging on idea one, where every unit gets a corresponding function
<fantasai> s/make things so we treat this like a unit/with this syntax which is easy to use and we'll want anyway, even if we have a more generic function. Also I think it would be nice if we could make it behave more like a unit.../
<emeyer> RESOLVED: add a function for every container query unit that allow to reference a named container
<emeyer> s/allow/allows/
<fantasai> cqi(<container-name>)

@kizu
Copy link
Member

kizu commented Mar 26, 2023

Very nice to see this resolved! I was experimenting with this a bit, and found kinda a workaround, where we could use custom properties defined via a @property to “store” the cq unit values on parents— https://codepen.io/kizu/pen/WNgKrpW

But having this available by just using functions would be really good.

@jsanthosh-godaddy
Copy link

following up to understand if there is a solution for this yet ?

@mirisuzanne
Copy link
Contributor

Yes, this has been accepted with a resolution above, and is marked as needing edits to the specification.

aarongable pushed a commit to chromium/chromium that referenced this issue Nov 23, 2023
With introduction of *progress() functions:
https://drafts.csswg.org/css-values-5/#media-progress-func
and
https://drafts.csswg.org/css-values-5/#container-progress-func
there is a need to save the identifier argument to these functions,
as later we need to update the computed value based on this identifier,
whether it's a media name or container name.

This is not possible, as the only literal terminator now is a number.
So, in order to be able to save it, string literal type is introduced.

Also, it can be useful to determine which container the container unit
refers to (e.g., cqi(<container-name>):
w3c/csswg-drafts#7858

Bug: 1503730
Change-Id: Ib9152f99b67eaefab4d96e7c37c1d0f5541194fb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5050160
Reviewed-by: Dominik Röttsches <drott@chromium.org>
Reviewed-by: Anders Hartvoll Ruud <andruud@chromium.org>
Commit-Queue: Daniil Sakhapov <sakhapov@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1228341}
@tux-
Copy link

tux- commented Sep 11, 2024

I was looking for a solution to select which container to use as containment in general (not just the cq* units. Like, which containment a fixed positioned element is relative to). Should this not be possible to control? Should this be another css value? Should this be included when using this method?

@kizu
Copy link
Member

kizu commented Sep 11, 2024

@tux- Anchor positioning will help with this, see this example: https://codepen.io/kizu/pen/wvLOZWV?editors=1100 — it is possible to use it to anchor an inner element to the outer container, and when using fixed positioning, it will also escape the overflow: hidden of the inner container.

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