[css-borders-4] Issues with listifying border-color · Issue #2532 · w3c/csswg-drafts (original) (raw)

This is related to #1172.

In the 2017 Tokyo F2F we resolved on listifying border-color with the design allowing for future listification of border-width and border-style.
We decided on border-color being the property that sets the number of borders, since a common case is having multiple borders with the same width and we didn't want authors to have to repeat the width of each stripe.

However, this has very unexpected and confusing repercussions. It means that setting border-color can increase the total border width. In the following:

border-width: 10px; border-color: red, black, white;

the resulting border width is actually 30px! (since border-width is expanded, per usual listification rules) This has never arisen before because none of our other listified properties stack this way, they are all independent layers.

Furthermore, another issue is that listification typically repeats the same syntax that a property already has. Since border-color accepts 1-4 colors for each side, this results in very weird listified syntax that inverts the relative power of space and comma to the exact opposite of how it would be expected to work. Look at this code and visual result:

border-color: skyblue orange yellowgreen indianred, black yellow

image

This is a completely nonsensical way to specify border colors. People think of all colors for a side as a group, they don't group colors by whether they are innermost or outermost.

For these reasons, @fantasai and I are exploring alternative syntaxes that cover most use cases with a more intuitive syntax.

The primary use cases we must definitely cover are:

Idea 1: Making border-color accept a list of color stops

While this may sound like a convenient re-use, it has several issues. Unlike gradients, in borders stripes are more often desired (are gradients even that useful here?) so we'd need to change how the syntax behaves anyway. Re-using a concept from somewhere else (like gradients) but subtly changing it is confusing.
Also, color stops are specified with absolute positions across the gradient line, whereas with borders you more often than not want them to "stack" and define widths instead of starts and ends (also so you can use fr units, which would be convenient here, as discussed above).

Idea 2: stripes() + border-color

This would define a stripes((<color> && <length-percentage>?)#) function that creates a one dimensional image. Lengths would also accept fr. This can be used anywhere that images are accepted, including backgrounds, as long as there is handling for 1-dimensional images. Possibly these could also be used in place of the gradient line in all our gradient functions.

Why 1-dimensional? Because otherwise, it would be problematic when combined with border-radius. It's tricky to define something reasonable for how a 2D image curves around the corner, and ignoring border-radius is suboptimal for most use cases.

So, the original use case of equal width black and white borders would be:

border-color: stripes(black, white);

Other cases:

Code Meaning
stripes(2px white, black 1fr, 2px white) Two 2px white borders with black in between them
stripes(red, green, blue) 3 equal width stripes, starting from red on the outside, green in the middle, blue on the inside
stripes(red 1fr, green 2fr, blue 1fr) 25% red on the outside, 50% green in the middle, 25% blue on the inside.
stripes(red) Same as border-color: red
stripes(red 30%, green) Same as stripes(red 30%, green 1fr): 30% red and 70% green.

Idea 3: Adding a border-stripes (name TBB) property that accepts a 1-dimensional image (as described above) or a list of colors and widths.

The main problem with this is the way it interacts with border-color. Unless there is a transparent stripe, border-color will have no effect when this property is set. One of the most confusing things about CSS is when a property enables/disables another property. I'd rather not introduce even more of that.