Circular Countdown Indicator

This currently requires IE 10?, 11+ and only partially works in Chrome as it involves animating gradient backgrounds which the spec says should work but has not been fully implemented in major browsers. In theory in the future this will work everywhere.

This idea was partly inspired by two things: Lea Verou's new book and Pecha Kucha. Those don't seem very related, so I'll explain. Inside the book is a section on pie charts, which can also be viewed on Smashing Magazine's site. Around the time I came across it in the book, my group at work selected me as the next to go for our "get to know each other better" talks. The format of those talks is a semi-relaxed Pecha Kucha: you give one presentation with about twenty slides that have one image each (no text) and spend about twenty seconds on each slide.

To show off my nerd cred I figured why not write the presentation in HTML? There's no restriction, that I know of, to make sure my presentation is in PowerPoint. A simple set of slides that animates automatically from right to left is easy, and while I could do 3D transitions that may distract too much from the content. However it still remains that each slide is only visible for twenty seconds. A bar along the bottom is easy; I thought I might try the pie chart idea as a circular indicator around the slide number.

Basic Setup

For reasons of trying things out, I decided not to go with the pseudo-element or SVG methods in the aforementioned pie chart article. This leaves doing this entirely with backgrounds. First, though, I'll work through the backgrounds.

Live Example


This sets up the size of our page indicator, centers the text, and adds the background circle. The circle is defined with a radial gradient so it can be set up to cover only part of the background and make the element appear smaller. This is fairly boring so next, like the original pie chart example, we're going to add the first part of the progress track.

This gives us half, but we don't really want that. So we're going to get on to the next part: covering it up. This enables us to reveal it as we need by rotation of the cover later. Below the example on the left has an added background (in the middle) to cover up the background we added above. The one on the right has the same added background but is rotated 15 degrees.

Live Example



The more we rotate the middle background the more of that half we reveal. We can set up an animation to do that as follows, which rotates the middle gradient 360° from its starting orientation.

However we now have a problem. Notice what happens after it passes half-way? It starts collapsing again and making itself smaller. That's not what we wanted. If we try rotating the bottom gradient, we end up with the same problem but for the other half of the circle. That won't work either.

On the other hand, each part works for their half of the circle. If we could combine both animations together, then we'd have a complete one that goes all the way around the circle without shrinking.

As they would have to trade off in the middle, if we look at how the right side animation ends, it is exactly the same as how the left side animation starts. We can use this to our advantage and make a quick change to middle and bottom gradients to turn the middle gradient in to the bottom gradient. After doing so we can then allow the bottom gradient to rotate as shown previously.

Take a look at the third stop. This is where our quick swap happens. We want it to happen very shortly after the second stop so the browser doesn't ignore it for being a dupe but has almost no time to transition the change. If we went straight from the 0% to 100% stops listed above, the browser would try to transition the colors and we would get strange color fading as the backgrounds rotated.

Finally let's combine the above @keyframes with our element.

This will start over when it reaches the end, but to only run once I would recommend the following styles. The removal of infinite means it will run once by default and the addition of forwards tells the browser to keep the last state of the animation instead of resetting itself to the base value defined in the element's selector.

Where to go from here: further ideas

Throughout this article I've used a single value inside the indicator. This is because my original intent was to use this as a fancy progress indicator around the page number. To make it into a generic progress indicator suiting other circumstances, more markup could be added to show an ordered list of percentages and move them from right to left by various means.

For a complete all-in-one example of this, please see the demo page. Thank you for reading.