Intro: the Pie Timer article updated and continued
This exercise was triggered by the different variants described or linked in the page css-tricks.com/css-pie-timer-re-revisited.
- Kitty Giraudel's original 2012 CSS pie timer (codepen.io/KittyGiraudel/pen/BHEwo) needs 4
div
's and around 50 lines of normal CSS. - Her revisited version of April 12, 2021 (codepen.io/KittyGiraudel/pen/jOyZXNm
has only 1
div
and a:before
and:after
pseudo element. All together around 40 lines of CSS. It's IE-11 proof (here a stand-alone version to test IE-11, for IE-11 can't handle codepens). - Chris Coyier on May 11, 2021 made on the css-tricks page a future perspective with 1
div
, aconic-gradient
and the@property
rule. He wrote: "This should work in Chrome (but nothing else) for now". - But according to caniuse.com for the actual stable versions: supported by Chrome-90 (since Apr.13, 2021), Opera-75 (since Mar.24, 2021), Opera Mobile-62 (for Android, since Feb.16, 2021), Android/Chrome-Android (since Apr.18, 2021), and Edge-90 (since Apr.14, 2021). Not supported: IE-11, Firefox/FF-for-Android, Safari, Chrome/Safari-for-iOS, Samsung. Unknown: other browsers/OS.
- So today I checked Chris' test page: codepen.io/chriscoyier/pen/xxqwOPY in Chrome (vs 90.0.4430.212),
Opera (vs 76.0.4017.123), Edge (vs 90.0.818.66), Vivaldi (vs 3.8.2259.42), IE-11 and Firefox (vs 88.0.1); all on desktop.
Result: indeed supported by Chrome, Opera and Edge. Also supported by Vivaldi.
Not supported by IE-11 (= never), and not (yet) by Firefox.
My challenge was to find a cross browser solution, to get rid of one pseudo element, and to get the smallest amount of CSS lines for that. I guess I've baked
a tasty pie of 25 css-lines (uncompressed).
Step 1 to Step 5 is the buiding process, Step 6 is the result.
Step 1
Kitty's revised version has an animated :before
pseudo-element as mask for the right side. In order to save this pseudo-element, we can replace
the desired solid background color by a linear gradient background-image (of the div
itself) with the background color left,
the desired pie color right, and a sharp color stop halfway.
<div class="pie"></div>
.pie {
width: 70px;
height: 70px;
border: 2px solid DeepPink;
border-radius: 50%;
background-image: linear-gradient(90deg, Aquamarine 50%, DeepPink 50%);
position: relative;
}
Because the background-image is a background, it will end at the border of the circle: there is no need to set a hidden overflow at the moment.
Step 2
The hands are free to style an :after
pseudo-element: as right part column of the div
area, with the background-color
of the div
. The left side of the area can stay transparent to show the background-color of the div
layer.
.pie {
...
overflow: hidden;
}
.pie:after {
position: absolute;
left: 50%;
width: 50%;
height: 100%;
content: "";
background: Aquamarine;
}
Because the :after
is absolute positioned for independent manipulations, this time the div
needs the
{overflow: hidden;}
.
This way the pseudo-element is exactly covering the right half of the circle. It seems just the same as our starting image, but that's not true!
The difference is:
Step 3
Now the animation can take place: rotating the pseudo-element and revealing the pie. In order to see what happens: just one turn of 360deg.
.pie:after {
...
transform-origin: 0 50%;
animation: pieAniAfter 5s linear forwards;
}
@keyframes pieAniAfter {
0% {transform: rotate(0deg)}
100% {transform: rotate(360deg)}
}
Oops alert ! Halfway the rotation: the front of the :after
-color is eating the pie at 12 o'clock and later! Soon there is
no pie left...
So the animation has to stop at 180deg. That is this one:
Step 4
That's o.k. now.
.pie:after {
...
animation: pieAniAfterHalf 2.5s linear forwards;
}
@keyframes pieAniAfterHalf {
0% {transform: rotate(0deg)}
100% {transform: rotate(180deg)}
}
And the filling of the other half?
Step 5
The magic switch ! - For the second half the we can recycle the useless :after
-rules.
In this case the opposite of what we have done: not revealing the right side, but filling the left side with the pie color.
Or: instead of "rotating the negative" we can "rotate the positive". To get the positive turn is easy: just change the background-color of the
:after
into the pie color, and let the rotation start again at the top.
Note: the left side of the :after
area can stay transparent again: first to show the (disappearing) background-color of the
div
layer, and after 12 o'clock to keep the pie color of the div
on the right side alive: no harm.
.pie:after {
...
background: DeepPink; animation: pieAniAfterHalf 2.5s linear forwards;
}
Step 6: the result
The only thing resting is to glue together the results of Step 4 and Step 5, in one combined animation with a sharp switch at 180deg. Also the
temporary forwards
of the animation can change into infinite
for endless spinning.
The definitive pie timer and code is:
<div class="pie"></div>
.pie {
width: 70px;
height: 70px;
border: 2px solid DeepPink;
border-radius: 50%;
background-image: linear-gradient(90deg, Aquamarine 50%, DeepPink 50%);
position: relative;
overflow: hidden;
}
.pie:after {
position: absolute;
left: 50%;
width: 50%;
height: 100%;
content: "";
background: Aquamarine;
transform-origin: 0 50%;
animation: pieAniAfter 5s linear infinite;
}
@keyframes pieAniAfter {
0% { transform: rotate(0deg); background: Aquamarine; }
49.99% { transform: rotate(180deg); background: Aquamarine; }
50% { transform: rotate(0deg); background: DeepPink; }
99.99% { transform: rotate(180deg); background: DeepPink; }
100% { transform: rotate(0deg); background: Aquamarine; }
}
Evaluation
Tested and supported in: Firefox, Chrome, Opera, Vivaldi, IE-11, MS-Edge; all on desktop.
Not tested: tablets and the arsenal of mobile devices, but I assume they don't perform worse than IE-11.
The clean result without the steps is on this page:
Francky Kleyneman
May 25, 2021