- From: Dael Jackson <daelcss@gmail.com>
- Date: Wed, 24 Sep 2025 19:11:43 -0400
- To: www-style@w3.org
========================================= These are the official CSSWG minutes. Unless you're correcting the minutes, please respond by starting a new thread with an appropriate subject line. ========================================= CSS Values 5 ------------ - RESOLVED: Make type(<url>) invalid in the attr() function (for now) (Issue #5079: attr()'s url type seems wrong) - RESOLVED: Simplify as much as possible (combining items when it can) for computed value (Issue #12290: Computed (vs used) value of mix() functions) - RESOLVED: Work on this in the next level (in consideration of all the complications outlined above) (Issue #11941: Allow `if()` in descriptors) - RESOLVED: type() values are parsed just as in custom properties. Other attr() type values (units % etc) are literals. Add a 'number' keyword for literal numbers (Issue #12479: Clarify how `<attr-unit>` should be parsed) - RESOLVED: Add color-scheme() test to both @container queries and if(). Open issue on what color-scheme() returns when used in color-scheme property (Issue #10577: Using `if()` to do dark/light switching of image urls) - RESOLVED: Explore options for making a syntactic distinction between input and interpolation options (Issue #12348: *-interpolate() grammar can lead to confusing values) ===== FULL MEETING MINUTES ====== Agenda: https://lists.w3.org/Archives/Public/www-style/2025Sep/0015.html Present: Tab Atkins-Bittner Kevin Babbitt Oriol Brufau Emilio Cobos Álvarez Yehonatan Daniv Elika Etemad Roman Komarov Alan Stearns Miriam Suzanne Anne van Kesteren Lea Verou Scribe: fantasai Scribe's scribe: emilio, TabAtkins CSS Values Level 5 ================== attr()'s url type seems wrong ----------------------------- github: https://github.com/w3c/csswg-drafts/issues/5079 annevk: attr() started supporting types allowing to parse attributes according to specified CSS types annevk: Some issues here. annevk: One was about passing the base URL along. Some discussion about that, forget the outcome. astearns: Munira suggested making the type invalid annevk: That is my preferred solution as well annevk: Resolving as document stylesheet maybe works. But if you resolve and serialize, it ends up as all ASCII, which is all Western-centric. Not what you want to print. annevk: like domain name would become pyunicode annevk: If you want it as a formatting feature, you'd need to add a converter function annevk: which we haven't exposed previously, and has security implications annevk: Browsers have not yet converged on a single algorithm for that operation emilio: Multiple base URL is not an issue. emilio: That said, I don't disagree with making it invalid. annevk: So you'd parse it for each document separately? emilio: attr() is substituted at computed value time, so you need to have the element and the document annevk: So when you compute the value, you parse the attribute value emilio: Yes emilio: You can optimize some cases but basically yes annevk: So you go into CSSOM, you get attr() emilio: The stylesheet has a base URL of its own, but it's not the base URI we're talking about here. annevk: Does the CSSOM have an object representing attr() you can query? emilio: Maybe with typed OM emilio: But you don't know which element you're applying the function to emilio: It's likely that idk about typed OM internals much emilio: but I imagine it presents as a function value with a keyword inside emilio: Might be a string or whatever emilio: But it's tangential. You can share a stylesheet across multiple docs without an issue astearns: Problem is that making invalid breaks print formatters annevk: Yeah, some want to do things like print URL of the link. But then you run into the i18n problem. Only works well for ASCII inputs, and that doesn't feel responsible to standardize fantasai: was it the case that the existing formatters use a different syntax? In which case making type(<url>) invalid wouldn't change anything? fantasai: presumably they are stuck on whatever syntax they support fantasai: seems we could try to standardize what they support but dropping type() from the spec shouldn't change it fantasai: but agreed we shouldn't break their existing content fantasai: that'd be bad annevk: Unclear if they support the current syntax astearns: Could take a resolution that `type(<url>)` is invalid, hoping print formatters are not using that syntax yet? TabAtkins: I'm happy with that. TabAtkins: We can also put an allowance for e.g. non-security- sensitive uses such as printing annevk: Not so much security, but i18n concern annevk: If the idea of this function is to display the URL, then we should have a good way of displaying annevk: If we just echo the value, then it will work for Western docs but fall apart everywhere else annevk: In which case I'd rather avoid annevk: making something that works for a subset of the world astearns: By making invalid now, not blocking a future where we figure out how to make it work well for i18n annevk: Yes. We should probably get there eventually. Just not a priority to figure out for anyone atm astearns: Ok, let's take a resolution and see how Mike responds to it. PROPOSED: Make type(<url>) invalid in the attr() function (for now). <TabAtkins> +1 RESOLVED: Make type(<url>) invalid in the attr() function (for now). Computed (vs used) value of mix() functions ------------------------------------------- scribe: TabAtkins github: https://github.com/w3c/csswg-drafts/issues/12290 fantasai: we have mix() that compute a weighted average from a list of items and percents fantasai: sometimes you can compute it to a final value, others you need to keep values distinct until used value time fantasai: we have two ways of simplifying we could take fantasai: one is to simplify as much as possible, including collapsing some items in the list fantasai: or we can just simplify each argument, preserving the number of items fantasai: so your computed value serialization would be either a single value, or a list with same number of items as previous. no halfway point like in the first option fantasai: currently we've specced the second option since it seems simpler, wanted opinions <emilio> I think whatever calc() does? <TabAtkins> calc() does first options astearns: doesn't first option lose info? astearns: how would I be able to look at list of values and get an average if I didn't know how many items where there? fantasai: each item has a weight, so your combined item has the combined weight fantasai: [gives example] astearns: ah, makes sense <lea> no opinion either astearns: slight preference for second, it preserves more of author intent astearns: and this is hopefully an edge case <lea> +1 <kbabbitt> also lean slightly toward option 2 <lea> What does min()/max() do? That might be a better precedent than calc() as it has multiple arguments too TabAtkins: Emilio commented in chat, seemed to lean option 1 emilio: is there a reason to not be consistent with calc? max simplification? fantasai: calc() is hierarchical, you kinda combine things that are adjacent until they can't be combined any more fantasai: in mix(), if first and last can be combined, middle can't, you'll get a combined item that has to go first or last... emilio: I think we should simplify nested mix() if possible, and that bubbles fantasai: yes, if you can collapse a mix() into one value, you do that. this is if at least one item can't be combined emilio: ah kk, thought you were never simplifying fantasai: nah, just if one item can't be simplified TabAtkins: min()/max() simplify by combining items, so that's a precedent TabAtkins: from some feedback from smfr back in the day astearns: should we go with option 1 then, for precedent? fantasai: it's a little easier for min/max since you just drop some, while here you have to change values, but it's certainly doable astearns: so proposed is to simplify as much as possible (combining items when it can) for computed value fantasai: I feel like manipulating the result will be odd, but... RESOLVED: simplify as much as possible (combining items when it can) for computed value Allow `if()` in descriptors --------------------------- scribe: fantasai github: https://github.com/w3c/csswg-drafts/issues/11941 TabAtkins: We have if() function which allows conditional tests. But only works in properties, because substitution functions are only defined in that context TabAtkins: but there are good use cases for being able to use if() with global tests like MQ TabAtkins: It could be done by using conditional at-rules today TabAtkins: if() is a nice syntactic convenience. TabAtkins: Anders says it's doable as long as we're clear which tests can be used outside an element context TabAtkins: I agree, should be useful. Right now just style query and color scheme query that we'd have to turn off. But doable TabAtkins: So I suggest we accept this feature, spec text TBD <lea> +1, many upsides, little to no downsides fantasai: I think it makes sense, but rather than excluding we should use an allowlist TabAtkins: agree fantasai: like there's a lot of variable stuff we can't do outside of an element context emilio: relatedly, there might be descriptors (e.g. @font-face) ... emilio: even in the case in the OP, @font-face is exposed to the FontFace API emilio: It's fairly different from media case emilio: I'm not sure how we should expose these values when you ask for them emilio: Seems weird to do the substitution when you do the getter emilio: requires updating style information, it's a bit annoying TabAtkins: currently those return strings TabAtkins: so I think it's fine? TabAtkins: we'd have to define how substitutions are reflected TabAtkins: and I think it's fine to say that the OM doesn't reflect substitutions emilio: That means the programmatic functions need to accept these, and those are exposed to workers, which is annoying emilio: There's a lot of edge cases to think about emilio: And that's just the @font-face ones emilio: And then @page stuff might affect MQ? astearns: So seems useful thing, but complications to work through. lea: Do we need to exclude variables syntactically? lea: Could define that variables resolve to their initial value. lea: idk if web compatible lea: but as an author, that's what I would expect TabAtkins: I would say that those tests, not on allow list, would just resolve to false TabAtkins: that would potentially allow us to turn on some tests in the future fantasai: given all that, I think we should maybe defer this to later... I don't want us to spend tons of times going down the rabbit holes and delaying if() on elements fantasai: so maybe say this is a good idea, but for the next level. sounds like it'll be a bunch of work on the spec and impl side, for something that is technically doable right now in other ways <emilio> +1 fantasai: so I worry if we batch it all together it'll be slower to get the core feature interoperable astearns: so we could resolve to accept it but punt to the next level. no more delay needed astearns: agree we shouldn't gate the existing if() on this <TabAtkins> +1 PROPOSED: Work on this in the next level. RESOLVED: Work on this in the next level (in consideration of all the complications outlined above). Clarify how `<attr-unit>` should be parsed ------------------------------------------ github: https://github.com/w3c/csswg-drafts/issues/12479 TabAtkins: Right now stuff for <attr-unit> production says "take this numerical attribute and pretend it's a pixel value" TabAtkins: says to parse it as a <number> TabAtkins: How literal are we about that? Is it a NUMBER token from Syntax? Or a <number> value from values? TabAtkins: the latter allows all the math functions TabAtkins: we need to clarify the spec in either direction TabAtkins: an earlier version of extended attr() was very specifically only looking for number tokens TabAtkins: for implementation simplicity reasons TabAtkins: it solved the use cases and was easy to do TabAtkins: as you allow more complicated things, it becomes more complicated TabAtkins: probably not worse than allowing more complexity in other values? TabAtkins: originally we added calc(), and then a jillion more math functions fantasai: this brings up interesting question fantasai: do we want to distinguish between CSS types (which should parse as full CSS) but have a different syntax for simple things fantasai: like "just a number" fantasai: for some core types like number... for string type we have a special type that doesn't do CSS parsing and just uses the attr value, so we already have cases for this distinction fantasai: so maybe this is a case where we distinguish fantasai: if you want CSS length values, use type(<length>), if you want CSS numbers, use type(<number.) fantasai: but if you just want a number interpreted as px, use this other syntax fantasai: and maybe that syntax is just the syntax we had before, with the keywords emilio: What is the behavior with custom properties? emilio: I would assume you ? parse calc() there emilio: consistency with that would be fair fantasai: This would mean any type() annotation is consistent with properties, but attr() would allow some extra things emilio: Agree that a raw number makes sense fantasai: Yeah, raw number with a unit appended, and a raw string, those are the special things we should be able to do astearns: We could take a resolution to define the type() parsing and have a new issue for extending the attr() for these raw types TabAtkins: This issue is about the unit keywords, not type() function TabAtkins: I'm happy with the proposal, where type keywords work for raw values, and anything with type() function is a CSS parse. TabAtkins: Probably means we want to add one more keyword for number, for raw numbers TabAtkins: currently we have raw-string, all the units, and % fantasai: So you're proposing raw-number? <TabAtkins> proposed: all the unit/% keywords are "raw number" - only a literal number. Add raw-number that's the same without a unit. All type() values are CSS-parsed, so type(<number>) allows calc()/etc PROPOSED: type() values are parsed just as in custom properties. Other attr() type values (units % etc) are literals. emilio: seems fair. I wish the keyword was just 'number'. It's a fairly common use cases, and 90% of use cases would be covered by it. emilio: raw-string is the default, so right now you don't have to type it TabAtkins: I'm fine with plain 'number'. PROPOSED: type() values are parsed just as in custom properties. Other attr() type values (units % etc) are literals. Add a 'number' keyword for literal numbers. RESOLVED: type() values are parsed just as in custom properties. Other attr() type values (units % etc) are literals. Add a 'number' keyword for literal numbers. Using `if()` to do dark/light switching of image urls ----------------------------------------------------- github: https://github.com/w3c/csswg-drafts/issues/10577 astearns: proposed to add a color-scheme() test to if() <TabAtkins> add color-scheme() test to if(), which tests the used color scheme on the element fantasai: is that cyclic? emilio: should we look at inherited value? TabAtkins: not cyclic because wouldn't work on color-scheme property TabAtkins: Looking at parent color-scheme wouldn't be useful. TabAtkins: It's not a complicated dependency, so should be straightforward. TabAtkins: we can make color-scheme() test fail in color-scheme property. emilio: There are typed custom properties as well... TabAtkins: We already have spec mechanisms to handle arbitrarily complex dependency chains accurately TabAtkins: this would add a dependency in TabAtkins: same as using a style test depends on custom property TabAtkins: thing to be concerned about is if likely that future language editions would create cycles that aren't already present TabAtkins: but I think it's safe to say that color-scheme won't depend on anything in the future fantasai: I defer to impls on implementability fantasai: but if we'll have special behavior on color-scheme prop to have it work, we should do the same as font-size/em fantasai: it also makes a somewhat useful thing - you can do the opposite color scheme of your parent astearns: Question of whether to add color-scheme() to container queries as well fantasai: if we're doing the hard one we should do the easy one :) <lea> +1 for color-scheme() on color-scheme resolving to parent color-scheme. I wish we had done that with var() too TabAtkins: Agree we should keep them in sync. PROPOSED: Add color-scheme() test to both @container queries and if(). Open question on what color-scheme() checks when in the color-scheme property. fantasai: Can we just resolve on the color-scheme() checks parent color-scheme? TabAtkins: unsure, let's leave it unresolved and discuss in other issue RESOLVED: Add color-scheme() test to both @container queries and if(). Open issue on what color-scheme() returns when used in color-scheme property. *-interpolate() grammar can lead to confusing values ---------------------------------------------------- github: https://github.com/w3c/csswg-drafts/issues/12348 TabAtkins: kbabbitt noted that the interpolate puts the value we're interpolating first, then options, then a list of stops TabAtkins: he points out that this looks confusing because some of the options can be affecting output values <TabAtkins> background-color: color-interpolate(300px in hsl, 200px: red, 500px: green, 600px: blue); TabAtkins: but are placed next to the input value TabAtkins: 300px in hsl loos like it's modifying 300px TabAtkins: wanted to see if we could rearrange syntax to make it less confusing TabAtkins: oriol's suggestion was to put the options first TabAtkins: this puts the options close to the 'interpolate(' word <TabAtkins> color-interpolate(in hsl / 300px, 200px: red, 500px: green, 600px: blue) TabAtkins: uses a slash to separate the value out, to avoid syntactic ambiguity lea: Not a strong objection, but I would prefer to avoid mixing slashes vs commas, because CSS is inconsistent in how it handles it lea: can we use a keyword? <lea> color-interpolate(in hsl at 300px, 200px: red, 500px: green, 600px: blue) fantasai: I haven't looked at this issue, but here's a wild idea. all the other values have a colon, what if you said `300px: in hsl` fantasai: so the first value is what we're interpolating, and options for the values oriol: Another point is, I believe we can just use a comma as a separator as there's no grammar overlap oriol: agree with Lea that mixing slash and comma is a bit weird. so I think we can just use a comma lea: Syntactically we want to distinguish prelude from list lea: So we want it to not look the same fantasai: I don't love having them in a different order. putting the value, the core thing you're acting on, last... <lea> `color-interpolate(at 300px in hsl, 200px: red, 500px: green, 600px: blue)` seems ok to me? fantasai: it's also often not '300px', it's something complicated like a var() fantasai: it's one of the most important parts of the function, the first thing you'll think about astearns: Sounds like we don't have consensus on a direction yet. RESOLVED: Explore options for making a syntactic distinction between input and interpolation options.
Received on Wednesday, 24 September 2025 23:12:14 UTC