Let’s begin with a simple div-element rotation and some HTML to start things off with.

<div class="radial-progress">

<div class="circle">

<div class="fill"></div>

</div>

</div>

“radial-progress” will be our root while “circle” will contain anything pertaining to the circle/pie chart we intend to draw.

Colors & Size

“radial-progress” should have a background-color while “fill” should have a color as well.

.radial-progress {

@circle-background: #d6dadc;

@circle-color: #97a71d;

background-color: @circle-background;

.circle .fill {

background-color: @circle-color;

}

}

The entire thing should also have a size:

.radial-progress {

@circle-size: 120px;

width: @circle-size;

height: @circle-size;

.circle .fill {

width: @circle-size;

height: @circle-size;

}

}

Rotation

To rotate the “fill” we preliminarily use some Javascript to set the “transform: rotate()” style.

var transform_styles = ['-webkit-transform',

'-ms-transform',

'transform'];

window.randomize = function() {

var rotation = Math.floor(Math.random() * 360);

for(i in transform_styles) {

$('.circle .fill').css(transform_styles[i],

'rotate(' + rotation + 'deg)');

}

}

The “random” behavior is used for demonstration purposes. Note however how we make the “fill” element turn a full 360º. For the time being we will think of 360º as 100% and e.g. 90º as 25%.

The rotation animation is of course the one we want to animate, so lets add a transition length variable and the css property to “fill”:

.radial-progress {

@transition-length: 1s;

.circle .fill {

transition: -webkit-transform @transition-length;

transition: -ms-transform @transition-length;

transition: transform @transition-length;

}

}

Clipping

Rotating a full circle is no fun, there is simply nothing to see because it is, well… round.

A spinning circle. No really, it’s spinning right now!

That is why we begin with a half-circle. To do that, we use the CSS clip property. It allows us to make only a specific area of an element visible.

Let’s show only the left half of the circle.

.radial-progress {

.circle .fill {

position: absolute;

/* rect(<top>, <right>, <bottom>, <left>) */

clip: rect(0px, @circle-size/2, @circle-size, 0px);

}

}

We also set the “fill” position to “absolute”, since “clip” will only work on elements positioned that way.

Smoothing the Edges

If you are using Chrome, you will very likely see jagged edges when our div is rotated.

Jagged edges in Chrome, when rotating elements.

You can avoid this issue by setting the CSS property “-webkit-backface-visibility” to “hidden”.

.radial-progress {

.circle .fill {

-webkit-backface-visibility: hidden;

}

}

You can view the intermediate jsfiddle result of all this before we continue with the next part.

That’s no Circle?!

No, it’s not, great observational skills there ☺

Let’s make it one then! All we need to do is set the border radius to 50%.

.radial-progress {

border-radius: 50%;

.circle .fill {

border-radius: 50%;

}

}

Setting border-radius to 50% on an element makes it a circle.

Masks

Remember how we decided that 90º rotation should be 25% etc.? We can get closer to that representation by hiding the “fill” when it is in the left half of the circle.

The half-circle is only visible in the left half of the circle.

To do that we once again use the “clip” CSS property. This time we put the “fill” inside another element, which itself is clipped, essentially creating a “mask”.

<div class="radial-progress">

<div class="circle">

<div class="mask">

<div class="fill"></div>

</div>

</div>

</div>

The mask has the same CSS properties as “fill”, with the transition and background-color properties being the exception. Since we only want to show the half-circle on the right side of the circle, we mirror the clipping rectangle of the half-circle:

.radial-progress {

.circle {

.mask {

/* rect(<top>, <right>, <bottom>, <left>) */

clip: rect(0px,@circle-size,@circle-size,@circle-size/2);

.fill {

clip: rect(0px,@circle-size/2,@circle-size,0px);

}

}

}

I recommend fiddling with the clipping areas to get a feel for how they work.

Two Halfs to a Circle

Note how in the previous part the circle moved into the left half again once it passed 180º.

Half circle disappearing behind the mask

We should limit it to only move 180º and consider that 100%.

window.randomize = function() {

var rotation = Math.floor(Math.random() * 180);

var fill_rotation = rotation / 2;

for(i in transform_styles) {

$('.circle .fill').css(transform_styles[i],

'rotate(' + fill_rotation + 'deg)');

}

}

That change will however leave us with only half a radial progress bar. So let’s add another half-circle, what could possibly go wrong?!