Learn CSS Visually! Every single CSS property visualized in this pictorial CSS guide book!
⭐⭐⭐⭐ and 1/2⭐ - owned by over 27.1K readers.
Get this CSS book in PDF format, on Amazon or start reading this css book on your Kindle device today!
Making Pie Chart And Wavy Progress Bars In CSS
I can't tell you how many times I needed to create rotating progress bar in CSS. And every time I couldn't find a simple solution. Most demos and libraries I found produced too much complicated CSS or JavaScript code.
Finaly I found some time to make my own and share it with the world. It's not perfect! But it serves the purpose I need, and should be easy to modify to match your own needs.
This tutorial is for someone who is searching Google for simple circular progress bar CSS code. Or maybe you're developing your own round progress bar from scratch for a library or an extension of some sorts. Then you can just copy this code as a starting point.
I know people are looking for this because I used to be one of them when I was working on a project for work. I ended up using someone else's library, and even though it was way over-complicated, we were on a tight deadline and had to implement something fast.
However, it's incredibly difficult to find simple vanilla code for this. So I made my own.
Wavy Progress Bar
So I got carried away and also made this wavy progress bar from code developed for this tutorial 🙂.
Here's the final version of the wavy progress bar which consists of many circular pie chart animations. In this tutorial I'll drop some code I wrote to make my own simple version of the pie chart animation.
There are many use cases for a rotary dial: mini clocks, progress bars, timers, indicators for number of characters left in a textarea, and so on. But there isn't a standard way of doing a circular pie chart in CSS.
But Let's Start From The Beginning - Creating Rotary Dials With CSS
CSS doesn't have a special property for creating simple pie charts. This is why often you will find pie chart libraries with elaborate code that border on brute force hacks.
But a simple pie chart can be created by combining several CSS properties as shown in this tutorial.
CSS Pie Chart Demo
First let's take a look at what we're creating here.
Here is the complete pie chart demo:
How Does It Work?
To make this effect with pure CSS you need to do some smoke and mirror. This demo consists of two elements representing each half of the circle. As long as you are rotating the dial in one direction, pure CSS is enough.
The pie chart consists of parent container.
Two more containers matching parent dimensions represent two sides of the dial.
Then inside those two containers there is an element with solid color.
Rotating those inner-most elements produces a pie chart effect.
Important: Each side rotates independently of the other.
But you have to rotate them one half at a time.
Angles between 0 and 180 are represented by the right half.
Angles between 180 and 360 are represented by the left half.
How It Was Made
This is a simplified version of the demo, just making one side work first.
Putting it all together, we get something like this:
The other half (left side) is almost identical, you just flip the box around.
The trick is to set the inner block with solid color (orangered in this case) to half of the container's width and displace its center with transform-origin property.
Because the solid fill is inside another HTML element with overflow:hidden, and because we only see half of the element, it creates an illusion of a clock-like animation.
This CSS pie chart animation was created by using a combination of CSS properties.
Here's a list of all other properties I had to use to build this demo:
- border-radius: 50%; add rounded corners.
- overflow: hidden; don't draw outside element's boundaries.
- transform: rotate(90deg) rotates element around its mid-point (center.)
- transition: 0.4s defines animation delay.
- transform-origin: 50px 50px changes center point of an element.
Side note:
- :after and :before pseudo-selectors.
Every HTML element has a hidden :before and :after selectors. They are originally invisible and will not be rendered unless you set content: '' property on them:
div:after {
content: ''
}
div:before {
content: ''
}
So basically, each HTML element is 3 in 1. At first I thought it was perfect, because the pie chart contains exactly two halves to create the circular progress bar.
My first idea was to use pseudo selectors to create both sides. But I realized I need a second level of depth in element hierarchy to create the rotating effect.
Furthermore browser support was questionable and awkward JavaScript selector model is either not supported everywhere or just generally cumbersome to implement.
CSS Code
The minimum CSS required to build rotary dial is as follows.
Note the parent container is .pie. It will be also assigned an id for targeting.
.pie {
position: relative;
width: 200px;
height: 200px;
background: orangered;
border-radius: 50%;
overflow: hidden;
}
.sides {
position: relative;
width: inherit;
height: inherit
}
.sides .left, .sides .right {
position: absolute;
top: 0;
display: block;
width: 200px;
height: 200px;
overflow: hidden;
transform: rotate(0);
}
.sides .left {
left: -100px
}
.sides .right {
left: 100px
}
.half {
width: 100px;
height: 200px;
transition: 0.4s;
}
.sides .left .half {
left: 100px;
position: absolute;
background: white;
transform-origin: 100px 100px
}
.sides .right .half {
position: absolute;
background: white;
transform-origin: 0 100px
}
.occluder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.occlusion {
position: relative;
display: block;
background: white;
width: 80px;
height: 80px;
border-radius: 50%;
}
HTML Scaffold
Here's our HTML scaffold. To target this container from JavaScript #demo id was used:
<div id = "demo" class = "f v h">
<div class = "pie" data-degree = 0>
<div class = "sides">
<div class = "left"><div class = "half"></div></div>
<div class = "right"><div class = "half"></div></div>
</div>
<div class = "f v h occluder">
<div class = "occlusion"></div>
</div>
</div>
</div>
Animating The Pie Chart
The CSS animation is controlled by transition: 0.4s property. That means when it's present, any new added properties and values will be automatically animated on that element.
You still need to change it with JavaScript directly by changing style.transform property or at least by adding a predefined class to the element (one of the halves.)
But because we have two halves, additional magic must take place. And without JavaScript it would be difficult or impossible (let me know on Twitter if you figure it out) to do.
Ugly But Necessary
All I wanted to create was pie chart animation in pure CSS for a quick project. This code can be easily adapted to frameworks or libraries like React, Vue and Angular.
This function rotate_pie which takes two arguments: parent container in string format and the degree will take care of everything.
/*
This function will rotate a pie chart
based on angle in degrees;
container value = '#parent'
degree value = 45
*/
function rotate_pie(container, degree) {
const parent = $(${container})
const left = $(${container} .sides .left .half)
const right = $(${container} .sides .right .half)
if (!parent.dataset.degree)
parent.dataset.degree = 0
if (parent) {
if (degree >= 0 && degree <= 180) {
if (parent.dataset.degree > 180) {
left.style.transform = rotate(0deg)
setTimeout(()=>{right.style.transform = rotate(${degree}deg)}, 401)
} else
right.style.transform = rotate(${degree}deg)
} else if (degree >= 180) {
if (parent.dataset.degree < 180) {
right.style.transform = rotate(180deg)
setTimeout(()=>{left.style.transform = rotate(${degree-180}deg)}, 401)
} else
left.style.transform = rotate(${degree-180}deg)
}
// memorize degree on container
parent.dataset.degree = degree
console.log(Degree now is ${parent.dataset.degree})
}
}
If the degree is between 0 and 180, animate right half. If degree is greater than 180 degrees, make sure the right half is fully animated first, and only then trigger animation of the second half.
For animation state with greater than 180 degrees, don't forget to also subtract 180 from originally passed degree value, because second half rotation also starts with 0, not 180.
Bonus Wavy Progress Bar
While I'm still focusing on this way of doing things, another idea came to mind. Why not apply the same strategy to create a wavy progress bar?
Learn CSS Visually! Every single CSS property visualized in this pictorial CSS guide book!
⭐⭐⭐⭐ and 1/2⭐ - owned by over 27.1K readers.
Get this CSS book in PDF format, on Amazon or start reading this css book on your Kindle device today!