One thing that caught my eye on the list of features for Lea Verou’s conic-gradient()
polyfill was the last item:
Supports double position syntax (two positions for the same color stop, as a shortcut for two consecutive color stops with the same color)
Surprisingly, I recently discovered most people aren’t even aware that double position for gradient stops is something that actually exists in the spec, so I decided to write about it.
According to the spec:
Specifying two locations makes it easier to create solid-color “stripes” in a gradient, without having to repeat the color twice.
I completely agree, this was the first thing I thought of when I became aware of this feature.
Let’s say we want to get the following result: a gradient with a bunch of equal width vertical stripes (which I picked up from an earlier post by Chris):
The hex values are: #5461c8
, #c724b1
, #e4002b
, #ff6900
, #f6be00
, #97d700
, #00ab84
and #00a3e0
.
Let’s first see how we’d CSS this without using double stop positions!
We have eight stripes, which makes each of them one-eighth of the gradient width. One eighth of 100%
is 12.5%
, so we go from one to the next at multiples of this value.
This means our linear-gradient()
looks as follows:
linear-gradient(90deg,
#5461c8 12.5% /* 1*12.5% */,
#c724b1 0, #c724b1 25% /* 2*12.5% */,
#e4002b 0, #e4002b 37.5% /* 3*12.5% */,
#ff6900 0, #ff6900 50% /* 4*12.5% */,
#f6be00 0, #f6be00 62.5% /* 5*12.5% */,
#97d700 0, #97d700 75% /* 6*12.5% */,
#00ab84 0, #00ab84 87.5% /* 7*12.5% */,
#00a3e0 0)
Note that we don’t need to repeat stop position %
values because, whenever a stop position is smaller than a previous one, we automatically have a sharp transition. That’s why it’s always safe to use 0
(which is always going to be smaller than any positive value) and have #c724b1 25%, #e4002b 0
instead of #c724b1 25%, #e4002b 25%
, for example. This is something that can make our life easier in the future if, for example, we decide we want to add two more stripes and make the stop positions multiples of 10%
.
Not too bad, especially compared to what gradient generators normally spit out. But if we decide one of those stripes in the middle doesn’t quite fit in with the others, then changing it to something else means updating in two places.
Again, not too bad and nothing we can’t get around with a little bit of help from a preprocessor:
$c: #5461c8 #c724b1 #e4002b #ff6900 #f6be00 #97d700 #00ab84 #00a3e0;
@function get-stops($c-list) {
$s-list: ();
$n: length($c-list);
$u: 100%/$n;
@for $i from 1 to $n {
$s-list: $s-list,
nth($c-list, $i) $i*$u,
nth($c-list, $i + 1) 0
}
@return $s-list
}
.strip {
background: linear-gradient(90deg, get-stops($c)))
}
This generates the exact CSS gradient we saw a bit earlier and now we don’t have to modify anything in two places anymore.
See the Pen by thebabydino (@thebabydino) on CodePen.
However, even if a preprocessor can save us from typing the same thing twice, it doesn’t eliminate repetition from the generated code.
And we may not always want to use a preprocessor. Leaving aside the fact that some people are stubborn or have an irrational fear or hate towards preprocessors, it sometimes feels a bit silly to use a loop.
For example, when we barely have anything to loop over! Let’s say we want to get a much simpler background
pattern, such as a diagonal hashes one, which I’d imagine is a much more common use case than an over-the-top rainbow one that’s probably not a good fit on most websites anyway.
This requires using repeating-linear-gradient()
and this means a bit of repetition, even if we don’t have the same long list of hex values as we did before:
repeating-linear-gradient(-45deg,
#ccc /* can't skip this, repeating gradient won't work */,
#ccc 2px,
transparent 0,
transparent 9px /* can't skip this either, tells where gradient repetition starts */)
Here, we cannot ditch the first and last stops because those are precisely what indicate how the gradient repeats within the rectangle defined by the background-size
.
If you want to understand why it’s better to use repeating-linear-gradient()
instead of a plain old linear-gradient()
combined with the proper background-size
in order to create such hashes, check out this other article I wrote a while ago.
This is precisely where such feature comes to the rescue — it allows us to avoid repetition in the final CSS code.
For the rainbow stripes case, our CSS becomes:
linear-gradient(90deg,
#5461c8 12.5%,
#c724b1 0 25%,
#e4002b 0 37.5%,
#ff6900 0 50%,
#f6be00 0 62.5%,
#97d700 0 75%,
#00ab84 0 87.5%,
#00a3e0 0)
And to recreate the hashes, we only need:
repeating-linear-gradient(-45deg,
#ccc 0 2px,
transparent 0 9px)
See the Pen by thebabydino (@thebabydino) on CodePen.
What about support? Well, glad you asked! It actually happens to be pretty good! It works in Safari, Chromium browsers (which now includes Edge as well!) and Firefox. Pre-Chromium Edge and maybe some mobile browsers could still hold you back, but if you don’t have to worry about providing support for every browser under the sun or it’s fine to provide a fallback, go ahead and start using this!
Those hashes are exactly the effect I was looking for!! Thank you so much
Nice article
What is the font in code snippets ???
Best article. Thank You so much update the news.
Thanks Ana, I didn’t know that. For those who have to support older browsers, but still want to use the double position syntax, there is this PostCSS plugin: https://github.com/jonathantneal/postcss-double-position-gradients
“Leaving aside the fact that some people are stubborn or have an irrational fear or hate towards preprocessors..” – what a strange thing to state.
Leaving aside the “fact” that sweeping generalisations can taint an otherwise solid article, are those “facts” or just your own bias on the matter?
Given it says “some”, not “all”, it’s in no way a “sweeping generalisation”.
And it’s not a “fact”, it’s a fact. Every single time I say CSS variables are not here to replace preprocessor ones, because they each have their own purpose, each is capable of doing something the other can’t, there are always people who start shrieking about how using preprocessors is an antipattern, how preprocessors are bad, bad, bad. And it’s been around since before CSS variables. I remember articles from 8 years ago about how using preprocessors only bloats the code. Which is silly, because it’s basically blaming the tool when the problem is really not understanding how it should be used.
In fairness, I would probably fall under that category.