[css-gaps-1] Serializing `column-rule` shorthand from separate longhands
In CSS Gaps 1, the column-rule shorthand has been extended to support lists of values. This expanded grammar introduces complexity when serializing the shorthand, especially if the individual longhand properties—column-rule-width, column-rule-style, and column-rule-color—contain differing lengths or patterns. For example:
column-rule-width: repeat(auto, thin medium);
column-rule-style: repeat(3, dotted) solid;
column-rule-color: red blue repeat(auto, green);
In such cases, it becomes unclear how the column-rule shorthand should be computed and serialized. What should the resulting computed value be when the longhand properties differ in structure?
Take a look at #7164.
7164 led to Appendix A: Coordinating List-Valued Properties, but I don't think that section is applicable in this case. Unlike backgrounds, transitions, or animations, there isn't a single "coordinating property" here: width, style, and color are all on equal footing, so to speak. We could define one of those as the coordinating property, but it's not clear to me that it would make things any simpler in this case. The sticking point I see is auto repeaters, because we don't know at computed-value time how many expansions will be generated.
I would look to CSSOM's Serializing CSS Values:
- Let shorthand be the first shorthand property, in preferred order, that exactly maps to all of the longhand properties in list.
- If there is no such shorthand or shorthand cannot exactly represent the values of all the properties in list, return the empty string.
- Otherwise, serialize a CSS value from a hypothetical declaration of the property shorthand with its value representing the combined values of the declarations in list.
If the repeaters happen to line up across the three properties, it's pretty trivial to construct an equivalent shorthand. If the repeaters don't line up exactly, it may still be possible to construct an equivalent shorthand by expanding integer repeaters. (The same should hold for specified values, btw.)
Yes, just as @kbabbitt noted, there is no single "coordinatring property" among the longhand properties (*-rule-width, *-rule-style and *-rule-color). Per the CSSOM's rule for serializing properties, the situations in which I think you cannot construct an equivalent shorthand are when:
-
Unaligned auto‑repeaters
If one or more longhands use anautorepeater in a way that doesn’t match the others you can’t form a unified shorthand. -
Mixed repeater + non‑repeater
A repeater is mixed with a non‑repeater within the same longhand and the non-repeater doesn't align with a non-repeater in other longhands. -
Co‑prime repeated values lengths
Two longhands have repeated value lists whose lengths are co‑prime, so their sequences never realign.
In other cases, I think it may be possible to expand the integer repeaters to the LCM of their repeat counts and serialize a hypothetically equivalent shorthand.
Examples
1a. Perfectly Aligned Auto‑Repeaters → Shorthand Possible
column-rule-width: repeat(auto, 10px);
column-rule-style: repeat(auto, solid);
column-rule-color: repeat(auto, red);
All three use repeat(auto, …) in the same position with the same repeated values length, so they line up:
column-rule: repeat(auto, 10px solid red);
1b. Unaligned Auto‑Repeaters → No Shorthand
column-rule-width: repeat(auto, 10px);
column-rule-style: thin solid;
column-rule-color: repeat(auto, red);
Here, only width and color use an auto‑repeater; style does not → cannot form a shorthand.
2. Mixed Repeater + Non‑Repeater
column-rule-width: repeat(3, 5px);
column-rule-style: repeat(2, solid) dashed;
column-rule-color: repeat(3, red);
*-rule-style has a non-repeater (dashed) that doesn't align with width and style → cannot form a shorthand.
3. Co‑Prime Repeated Value List Lengths → No Alignment
column-rule-width: repeat(2, 10px);
column-rule-style: repeat(3, solid hidden ridge);
column-rule-color: repeat(2, red green);
*-rule-style list length = 3, *-rule-color list length = 2 (co‑prime), so sequences never realign → cannot form a shorthand.
- Repeated Values Entries expanded up to LCM(lengths of repeated values):
*LCM(1, 3, 2) = 6
- width: 10px | 10px | 10px | 10px | 10px | 10px
- style: solid hidden ridge | solid hidden ridge
- color: red green | red green | red green
4. Integer Repeaters Align via LCM → Shorthand Possible
column-rule-width: repeat(2, 10px);
column-rule-style: repeat(3, solid);
column-rule-color: repeat(2, red);
- LCM(2, 3, 2) = 6
- Expand each to 6 entries → can form a shorthand:
column-rule: repeat(6, 10px solid red);
5. Different Repeat Counts and Repeated Value Lists Lengths, Can Still Align via LCM:
column-rule-width: repeat(3, 10px);
column-rule-style: repeat(2, solid hidden double ridge);
column-rule-color: repeat(4, red green);
- Repeat Count
- LCM (3, 2, 4): 12
- Repeated Values Entries expanded up to LCM(lengths of repeated values):
- LCM(1, 4, 2) = 4.
- width: 10px | 10px | 10px | 10px
- style: solid hidden double ridge
- color: red green | red green
- LCM(1, 4, 2) = 4.
column-rule shorthand can still be constructed.
column-rule: repeat(12, 10px solid red, 10px hidden green, 10px double red, 10px ridge green);
Thanks @oSamDavis.
A couple of observations:
- In cases where there are no repeaters, it should always be possible to line the lists up via LCM
- Integer repeaters can always be expanded to equivalent non-repeater lists
Given those two observations, I think it is in fact possible to produce a shorthand for case 3, though it would require expanding the lists out to 36 values each.
So a naive algorithm for serialization might be to first expand all integer repeaters; then if there are no unaligned auto repeaters, serialize using LCM. But that might go against author expectations in simple cases. For example, if I specify:
column-rule: repeat(5, thin solid black, thick solid gray);
That decomposes into:
column-rule-width: repeat(5, thin thick);
column-rule-style: repeat(5, solid solid);
column-rule-color: repeat(5, black gray);
And I might expect serialization of the shorthand to recompose to what was originally specified. Or maybe that would be too magical?
I think we need to figure out the right tradeoffs between implementation complexity and preserving what was originally specified. Agenda+ to take the WG's temperature on this.
The CSS Working Group just discussed [css-gaps-1] Serializing `column-rule` shorthand from separate longhands.
The full IRC log of that discussion
<Kurt> oSamDavis: column rule shorthand, with gap decorations, you can use a list and repeat syntax<Kurt> ...when you have longhand, the issue is when you have individual longhand properties that don't align
<Kurt> ...the question is how do you serialize or get shorthand from individual longhands
<Kurt> ...when no repeaters are used, you can line up using LCM, but using repeaters, you can expand and then using LCM
<Kurt> ...this would mean some cases don't preserve auto repeat syntax for column rule, we would see values blown up to match separate longhand
<Kurt> ...CSSOM serialization rules say either no shorthand or if you cannot represent, return empty string
<Kurt> ...how hard to we want to try to get shorthand, or if we don't align return empty string
<Kurt> astearns: not aware of escape hatch, where else is it used
<Kurt> oSamDavis: I have seen in border IIRC
<Kurt> ...not sure of specifics
<alisonmaher> q+
<Kurt> astearns: I'm not aware of any, but I might not know about it, where we go to great lengths to make a longer shorthand value in order to accurately represent the longhands, seems not useful
<astearns> ack alisonmaher
<Kurt> oSamDavis: I'm hearing we could return an empty string when it's difficult
<Kurt> almaher: do we have a precedent in grid
<Kurt> oSamDavis: I looked at grid, but grid's shorthand is can have columns or rows separated by a slash, so it's easier. Can have properties as part of shorthand, which is not the same as column rule
<Kurt> astearns: on this one, I think we need to take it back to the issue or do another call, need shorthand experts with strong opinions
<Kurt> ...I will tag folks in the issue, hopefully will define soon
@fantasai @tabatkins @emilio any shorthand opinions for this issue?
The CSS Working Group just discussed [css-gaps-1] Serializing `column-rule` shorthand from separate longhands, and agreed to the following:
RESOLVED: Serialize a shorthand if the longhands line up, otherwise return empty stringRESOLVED: this shorthand and its longhands should use consistent punctuation
The full IRC log of that discussion
<fantasai> oSamDavis: The gaps spec extended column-rule to support list of values<fantasai> oSamDavis: but this becomes tricky when we have separate longhand values that don't necessarily line up
<fantasai> oSamDavis: I put an example there
<fantasai> oSamDavis: e.g. auto-repeat, or not
<fantasai> oSamDavis: Kevin brought up idea of [missed]
<fantasai> oSamDavis: also separate problem with serialization
<fantasai> oSamDavis: if it's impossible to get from longhand can serialize as empty string
<kbabbitt> q+
<fantasai> oSamDavis: it's not impossible here, but challenging
<SebastianZ> q+
<fantasai> oSamDavis: Should we return empty string here, or try to repeat to get them to line up
<astearns> ack kbabbitt
<fantasai> kbabbitt: I think the tension here is how far do we want to make implementations go to be able to construct a shorthand when theoretically possible
<fantasai> kbabbitt: vs reflect what author originally specified
<fantasai> kbabbitt: I'm not sure what the right answer is
<fantasai> kbabbitt: don't want to go too far in reconstruction
<fantasai> kbabbitt: if the repeaters line up exactly, then reconstruct the shorthand; otherwise return empty string
<fantasai> kbabbitt: but would like more opinions
<astearns> ack SebastianZ
<fantasai> SebastianZ: I don't have an idea, but currently, these are not list-valued properties, right?
<fantasai> SebastianZ: they use spaces, not commas for values, right?
<fantasai> SebastianZ: and they're not linked, right?
<fantasai> SebastianZ: so that's difference to the thing we resolved on in 7164
<fantasai> SebastianZ: so resolution of that issue doesn't apply here
<fantasai> kbabbitt: There isn't a core property, they're all co-equal
<fantasai> SebastianZ: should we introduce one, say one is the coordinating list base property , and then treat it like list-valued properties?
<fantasai> https://www.w3.org/TR/css-values-4/#linked-properties
<fantasai> kbabbitt: Idk if that would work, because you can have auto-repeaters, and we don't know how many that expands to
<fantasai> kbabbitt: the way coordinated list valued properties work, coordinating property has a fixed number of properties, and others repeat to match it
<fantasai> SebastianZ: I'm just imagining if we introduce slashes for the shorthand, can we allow repeat in all of them?
<fantasai> SebastianZ: maybe use the values defined in each longhand to serialize the shorthand
<fantasai> oSamDavis: Like grid?
<fantasai> SebastianZ: you can still distinguish them because 2nd part of repeat function is different for each
<fantasai> SebastianZ: won't repeat them, but just serialize how they're written in the longhand
<fantasai> oSamDavis: Only kind of issue is if we introduce slashes, then default width might present bacjward compat issues, because slashes would b enew syntax
<fantasai> SebastianZ: well, repeat function is new
<fantasai> SebastianZ: but then current syntax would be legacy syntax
<fantasai> SebastianZ: so old one without slashes and new one with slashes
<fantasai> SebastianZ: but repeat functions by second param
<fantasai> SebastianZ: so don't necessarily need slashes between them
<astearns> ack fantasai
<astearns> fantasai: was wondering why we didn’t want to do a coordinated list property
<astearns> fantasai: but that was the coordinated repeat stuff
<fantasai> astearns: 3 options
<fantasai> astearns: combinatorial explosion
<fantasai> astearns: slashes
<fantasai> astearns: giving up and returning an empty string
<fantasai> fantasai: slashes?
<fantasai> SebastianZ: to distinguish the 3 types of values
<fantasai> fantasai: they're syntacticaly distinct already
<fantasai> SebastianZ: makes it easier to read
<fantasai> fantasai: just put them on different lines
<fantasai> ...
<astearns> fantasai: no slashes
<fantasai> fantasai: I think we should reserve punctuation for when we actually need syntactic disambiguation
<fantasai> SebastianZ: So we could just serialize the longhands in sequence
<fantasai> fantasai: without interleaving into a joint list
<fantasai> astearns: So just join the longhands with spaces
<fantasai> kbabbitt: just want to hear is to what extent we want to synthesize the list
<fantasai> fantasai: In background etc you can create a list of values, which allows you to specify the items that correspond together
<kbabbitt> column-rule: 1px solid red, repeat(auto, 1px solid black), 1px solid green, 1px solid blue;
<fantasai> fantasai: I guess if you can do that, then do that
<fantasai> fantasai: otherwise I guess returning empty string because you're out of sync is probably fine
<kbabbitt> PROPOSED: Serialize a shorthand if the longhands line up, otherwise return empty string
<fantasai> emilio: ... yeah, don't do that
<fantasai> emilio: if you combine them and then inherit, that would give you a different value
<fantasai> emilio: returning empty string is fine
<astearns> s/that/that (aligning misaligned things via LCM)/
<fantasai> SebastianZ: The shorthand is a list-valued property, but the longhands are not
<fantasai> fantasai: that's weird
<fantasai> SebastianZ: maybe that's the issue!
<kbabbitt> column-rule-color: red repeat(auto, black) green blue;
<fantasai> kbabbitt: the longhands can take lists, but they don't need the commas to disambiguate
<fantasai> fantasai: if you have a list that's comma-separated in the shorthand, should use commas in the longhands also
<fantasai> SebastianZ: Normally, would epxect to group the different longhands
<fantasai> SebastianZ: You group first width, then colors, then style
<fantasai> kbabbitt: that seems awkward to maintain
<astearns> (fantasai consults the spec)
<fantasai> SebastianZ: So before was one value each of width, color, style
<fantasai> SebastianZ: now extended to have multipel of these values
<fantasai> -> https://www.w3.org/TR/css-values-4/#linked-properties
<fantasai> fantasai: If we're doing coordinated lists, we should use coordinated list syntax, not something different
<fantasai> fantasai: should behave the same and use the same syntax
<fantasai> fantasai: If we need extensions such as repeat()s, then let's extend it
<fantasai> fantasai: but still should be compatible otherwise
<fantasai> kbabbitt: then which would be the base property?
<fantasai> ...
<fantasai> fantasai: maybe would need to take the max. Hard to say which shoudl be the base property
<fantasai> astearns: Way too much time on this issue
<fantasai> astearns: I'm not entirely sure how much ppl will care about the serialization of this shorthand
<fantasai> fantasai: when it's mismatched
<fantasai> SebastianZ: so maybe serialze to empty string if not matched
<kbabbitt> PROPOSED: Serialize a shorthand if the longhands line up, otherwise return empty string
<kbabbitt> RESOLVED: Serialize a shorthand if the longhands line up, otherwise return empty string
<kbabbitt> PROPOSED: this shorthand and its longhands should use consistent punctuation
<kbabbitt> RESOLVED: this shorthand and its longhands should use consistent punctuation
So *-rule shorthands should serialize with an empty string when some but not all longhands use repeat(<auto-or-integer>, <list>) at the same position, with the same <auto-or-integer>, and with the same <list> length.
Is that correct?
That's how I understand the resolution, yes.