I was working on a thing the other day that needed a visible timer. There was UI precedent for this type of timer on the project. People didn’t want to see numbers ticking downward; it was more ideal to see a “bar” drain away from full to empty. I mention that because there are tons and tons of ways you could approach a “timer” UI. This isn’t an exploration of all of those (a search on CodePen would be more helpful there), but an exploration of the one way that was useful to me.
The kind of timer I needed was what the project called a “round time” bar. An action is performed. It may cause a round time, and most further actions are blocked until the round time is over. So, a very clear red bar that ticks away was the right UI. It gives a sense of rhythm and flow where you can kinda feel the end of the timer and time your next action.

linear
animation that shrinks the bar to zero.Setting this up is fairly easy…
Let’s give ourselves a parent/child thing, just in case we want to style the empty part of the container at some point.
<div class="round-time-bar">
<div></div>
</div>
For now, let’s just style the bar inside.
.round-time-bar div {
height: 5px;
background: linear-gradient(to bottom, red, #900);
}
That gives us a nice little red bar we can use for the time indicator.
Next we need to make it tick down, but here’s where we need to think about functionality. A timer like this needs to know how long it’s timing! We can give it that information right in the HTML. This doesn’t mean we’re avoiding JavaScript — we’re embracing it. We’re saying, “hey JavaScript, please give us the duration as a variable and we’ll take it from there.”
<div class="round-time-bar" style="--duration: 5;">
<div></div>
</div>
In fact, this way is very friendly to modern DOM-handling JavaScript. As long as that --variable
is correct, it is free to re-render that DOM element at any time and we can make sure the design handles that just fine. We’ll make a variation that does that.
For now, let’s make the animation happen. Good news, it’s easy. Here’s a one-liner keyframe:
@keyframes roundtime {
to {
/* More performant than animating `width` */
transform: scaleX(0);
}
}
We can “squish” the bar because the design of the bar doesn’t have anything that will look squished when we scale it horizontally. If we did, we could animate the width
. It’s not that big of a deal, especially since it doesn’t reflow anything else.
Now we apply it to the bar:
.round-time-bar div {
/* ... */
animation: roundtime calc(var(--duration) * 1s) steps(var(--duration)) forwards;
transform-origin: left center;
}
See how we’re yanking that --duration
variable to set the duration of the animation? That does the heavy lifting. I’m also using it to set the same number of steps()
so it “ticks” down. That “ticking” might be a visual UI thing that you like (I do), but it also accommodates the idea that JavaScript might re-render this bar at any time, and the ticks make it so you are less likely to notice. I used an integer for the duration value so that it could do double-duty like this.
If you want a smooth animation though, we could do that as a variation, like:
<div class="round-time-bar" data-style="smooth" ... />
Then not do the steps:
.round-time-bar[data-style="smooth"] div {
animation: roundtime calc(var(--duration) * 1s) linear forwards;
}
Note we’re also using a linear
animation, which seems to make sense for a timer. Time, as it were, doesn’t ease. Or does it? Whatever, it’s your call. If you want a timer that appears to speed up or slow down at certain points, go for it.
We can use the same variation data-attribute-driven API for things like color variations:
.round-time-bar[data-color="blue"] div {
background: linear-gradient(to bottom, #64b5f6, #1565c0);
}
And one final variation is making each “second” a fixed width. That way, a 10 second timer will literally look longer than a 5 second timer:
.round-time-bar[data-style="fixed"] div {
width: calc(var(--duration) * 5%);
}
Here’s the demo:
Notice the little trick in there for restarting CSS animation.
Oh, and hey, I know there is a <meter>
element which is maybe a bit more semantic, but it brings it’s own UI which isn’t animatable like I wanted things to be here — at least not without fighting it. But I wonder if it’s more accessible? Does it announce its current value in a useful way? Would it be a more accessible timer if we were updating a <meter>
in real-time with JavaScript? If anyone knows, I can link up a solution here.
Doesn’t using style require a CSP that allows inline styles (which IIUC is discouraged)?
I assume you could do:
and add
20secduration
to the class list fordiv.round-time-bar
.Also could you use
data-duration=20
and changevar(--duration)
toattr(data-duration)
?The
<progress>
element might be more semantically correct than<meter>
, not sure… either are bound to be more appropriate than a<div>
, that’s for sure.And
<progress>
can be styled in CSS. Animating the value, though, would probably need to be done in JavaScript (by manipulating itsvalue
attribute).meter
is announced asprogressbar
for assistive technologies. The current value is given, as well as the min and max values. The UI component here is generic and would need some aria attribute to mimic the behavior. I don’t really know how it is handle by the devices though. Anyway, we need more flexible styling options for native UI elements!I was curious to see how difficult it would be to make the bar incremental but also smoothly animate between the seconds. Turns out it’s pretty simple. Instead of setting the number of seconds with a variable, the number of seconds is set by the number of child objects you place into the container, each of which has an animation with an
n-1 seconds
delay on it, and the container is set to display them in reverse using flexbox.Link if anyone is interested:
This is sweet.
Very nice!
Thank you Chris Coyier.
I have been searching for this for days.
I’d love to add this timers to an image slides that I created, make it run with the slides simultaneously, something like the isntagram story. But I don’t know how to make this work.
Would appreciate some help.
I’m new to this.
Thank you again.
Is that a way to revert the animation ? To make timer colored bar complete (from left to right) instead of disappearing ?