[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
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:
- Multiple border stripes of equal width should be effortless, with no width duplication.
- Different width stripes with fixed ratios between them (e.g. two 1fr stripes with one 2fr color between them)
- A mix of fixed and flexible width stripes (e.g. two 1px black borders with blue between them that occupies the entire rest of the border).
fr
units deal very nicely with this. - We don't think different styles are particularly useful here. Almost all use cases we've seen are about solid borders. Therefore, we're ok with having multiple colors for different styles just be defined as a cutout of the solid case.
- Are different colors per side useful?
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.