Index Of /

CSS: conic-gradient() for a round progress component

Otober 28, 2019

Last week I had a really strange project for company building apps using blockchain technology. The task was pretty simple — to write HTML and CSS for the components that were previously designed and... no JavaScript at all. The reason was understandable (and arguable) — security, without client scripts nobody can steal the private keys from the app using any kind of XSS or similar.

But then one of the components surprised me — a round progress bar with more than one color:

... and then I found out that I cannot use inline SVG too ;-))

My first thought was: “Oh, no, I don't want to use rounded borders and make classes for every percentage point possible.” And the second: “hm, maybe I can do that with radial-gradient somehow?” (no, I can't)

But there is another type of gradients, not supported even by Firefox for now: conic-gradient, but Chrome and Safari are doing great, so if you are targeting the latest versions of mobile OSes — you can use them. And if you need it for charts or progress bars like me, you can have a nice fallback to linear-gradient as well. And here's how I did it.

Using CSS Variables

To make it easy to fall back, we'll have to use the same data twice — in the conic-gradient and the linear-gradient. So let's keep it in the CSS variables if you are not targeting IE, of course. The code for my element looks like this:

<div class="chart" style="--approved: 75%; --rejected: 15%;"></div>

Since we have two colors: green (approved) and red (rejected), and gradients are great in handling data in %, then all we have to do is to write some CSS.

Linear-gradient as a graceful degradation

First comes the fallback — a classic linear-gradient with color-stops at the --approved and --approved + --rejected percentages:

.chart { 
width: 180px;
background: linear-gradient(
to right,
green var(--approved),
red var(--approved),
red calc(var(--approved) + var(--rejected)),
#ccc calc(var(--approved) + var(--rejected))
);
}

Conical gradient for the browsers that supports it

And then the conical variant — checking for the support and then using the same color stops as before:

@supports (background: conic-gradient(#000, #000)) { 
.chart {
width: 144px;
height: 144px;
padding: 18px;
border-radius: 90px;
background: conic-gradient(
green var(--approved),
red var(--approved),
red calc(var(--approved) + var(--rejected)),
#ccc calc(var(--approved) + var(--rejected))
);
}
.chart--data {
width: 144px;
height: 144px;
background: white;
border-radius: 90px;
}
}

The result:

You can see, that additionally, I've put another element in the middle, to make the “hole” inside the progress, but you can play with the `-webkit-mask` properties if you need true transparency.

Hope that was helpful for somebody.

Andrey “Leechy” Lechev

Some frontender thoughts
Twitter, GitHub, LinkedIn