I hope you gulped down those two striped candy bars? If not, then just head over to my previous post:
Let's make and eat those CSS3 progress bars. π
Vaibhav Khulbe γ» Jun 19 '20
This time around, we're about to become a jeweller to make some progress rings! π Thanks to @yuvaraj's comment embedded below, I started coding this little project:
Nice article .. can you write about circular progress bars. ?
So what are we waiting for? Well...a GIF I suppose?
Finish off the HTML first π€ͺ
Because...well, you need something to style on? What we want to achieve is the following:
Let's wear those frontend glasses and inspect what we need to make this happen.
At its atomic level, we have a circle. But this is not your regular <div>
having a border-radius
of 50%
! We need to go through some cool SVG based tags for a better understanding:
-
<div>
: Well, just know it's short for Content Div ision element. οΌβο½βοΌ -
<svg>
: You use this when you need to have a set of a new coordinate system in your HTML body. Like if you want to define your own width and height and even some inner child elements to an object. Of course, it also acts as an embed to SVG shapes. -
<circle>
: As you might have guessed, you make...well...circles using this tag. They need to have a certain radius value.
So, we'll need:
- A container to hold the two rings.
- The two actual rings.
- For each ring, we need the
<svg>
element to draw the circular shape with an equally defined value of x and y coordinates along with its radius. - For the percentage value, a div with a heading and a
<span>
having that small "%" sign.
Here we go:
<div class="rings">
<div class="percent1">
<svg>
<circle cx="70" cy="70" r="70"></circle>
<circle cx="70" cy="70" r="70"></circle>
</svg>
<div class="number">
<h2>75<span>%</span></h2>
</div>
</div>
<div class="percent2">
<svg>
<circle cx="70" cy="70" r="70"></circle>
<circle cx="70" cy="70" r="70"></circle>
</svg>
<div class="number">
<h2>33<span>%</span></h2>
</div>
</div>
Let's make it look like a progress ring π
First, we need to give each of our elements a fixed width and height values so that they fit into the rings
container properly. Hence, we select the two rings, the svg and the circle elements as shown:
.percent1, .percent2, svg, circle {
width: 200px;
height: 200px;
}
Now let's make that base circle. We position this absolute to the svg element, set its fill
or color to none
because technically we don't need to have a color on the circle. For the width of the circle, we give it a length of 10
units or 10px. The greater its value, the thicker our circle outline will be. This is controlled by the stroke-width
attribute for the svg.
To add that gap you see on the top of each ring, we use the stroke-dasharray
and set it to an approximate value. I found 440
to be good. Then for the type of stroke, we need a circular one because it has a rounded corner perfectly suitable to show progress. This is controlled by the stroke-linecap
attribute. Here's what we've been up to:
circle {
position: absolute;
fill: none;
stroke-width: 10;
transform: translate(10px, 10px); /* This is to position it in the center */
stroke-dasharray: 440;
stroke-linecap: round;
}
We now use the nth-child()
pseudo-class to select the first element i.e. the ring behind the actual progress bar. We don't need any type of gap between the entire ring behind so we put the value of stroke-dashoffset
to 0
and give it a suitable stroke color.
Next, we want to make that progress bar over the top of the grey circle. This is the 2nd element in the HTML (remember we had 2 elements for each ring?) so with the same pseudo-class, we give it the gold
stroke, an animation
which runs for 1.5
seconds linearly and with a 1-second delay. If you're new to animations in CSS, read this documentation from MDN. In the actual animation definition, just reset the stroke-width
and the offset to 0
initially.
.percent1 circle:nth-child(2) {
stroke: gold;
animation: percent 1.5s linear;
animation-delay: 1s;
}
/* Animation definition */
@keyframes percent {
0% {
stroke-dashoffset: 0;
stroke-width: 0;
}
}
Time for some math...π₯΄ To set our progress bar to the exact percentage value defined inside the rings, we set the value of the stroke-dashoffset
as: calc(440 - (440 * 75) / 100)
Now what does that freaky formula means is:
- The
calc()
function in CSS allows us to perform such type of complex calculations. - First, we take the
stroke-dasharray
value of ourcircle
(440). - Next, we multiply it by the percentage value we need to display or render to the actual progress (75).
- Finally, we divide it with
100
to calculate the actual percentage value i.e. 75%.
So, our first progress ring in CSS looks like this:
.percent1 circle:nth-child(2) {
stroke-dashoffset: calc(440 - (440 * 75) / 100); /* Here's what's changed */
stroke: gold;
animation: percent 1.5s linear;
animation-delay: 1s;
}
We do a similar thing for the second ring. The only difference is that it's a rose-gold coloured and has a percentage value of 33
. It runs for a little longer with .2 seconds greater delay.
.percent2 circle:nth-child(2) {
stroke-dashoffset: calc(440 - (440 * 33) / 100);
stroke: salmon;
animation: percent 1.8s linear;
animation-delay: 1.2s;
}
There's nothing special about the CSS of actual percentage values. It's just centred in between, have the same color etc.
.number {
position: relative;
bottom: 190px;
right: -50px;
color: #fff;
}
h2 {
font-size: 48px;
}
span {
font-size: 24px;
opacity: .7;
}
.percent1 span {
color: gold;
}
.percent2 span {
color: salmon;
}
Tada! Those CSS rings are here. You made it. π₯³
If, for any reason you are stuck, then here's the CodePen demo for the same:
So, who's ready to wear these rings? π
Where to next? π€
This was entirely made with CSS, why not use some JavaScript or jQuery (if you don't hate it), to make the numbers go from 0 to 75%? It would look so cool! Get to know more about SVG and its CSS properties:
Thanks for reading, I appreciate it! Have a good day. (βΏββΏββΏ)
May we suggest cleaning out your fans? Or earplugs. π
β Microsoft Developer UK (@msdevUK) June 21, 2020
Source: https://t.co/rcuLDnEWdx#DevHumour #Developer #Programming #ICYMI pic.twitter.com/7kZ2UjSxeZ
Top comments (4)
This is so cool. Why haven't I thought of it.
Definitely gonna try with JS.
Awesome pawsome! πΎ
Wow that looks great!
Thank you Emma! π