I not too long ago up to date my portfolio at johnrhea.com. (For those who’re trying so as to add a CSS or front-end engineer with storytelling and animation abilities to your staff, I’m your man.) I favored the look of a sequence of planets I’d created for one more private mission and determined to reuse them on my new web site. A part of that was additionally reusing an animation I’d constructed circa 2019, the place a moon orbited across the planet.
Initially, I simply plopped the animations into the brand new web site, solely altering the items (em
items to viewport items utilizing some sophisticated math that I used to be very, very happy with) in order that they’d scale correctly as a result of I’m… environment friendly with my time. Nonetheless, on cell, the planet would transfer up a couple of pixels and down a couple of pixels because the moons orbited round it. I suspected the plopped-in animation was the wrongdoer (it wasn’t, however at the very least I received some optimized animation and an article out of the deal).
Right here’s the unique animation:
My preliminary animation for the moon ran for 60 seconds. I’m folding it inside a disclosure widget as a result of, at 141 strains, it’s silly lengthy (and, as we’ll see, emphasis on the silly). Right here it’s in all its “glory”:
Open code
#moon1 {
animation: moon-one 60s infinite;
}
@keyframes moon-one {
0% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
5% {
rework: translate(-3.51217391vw, 3.50608696vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
9.9% {
z-index: 2;
}
10% {
rework: translate(-5.01043478vw, 6.511304348vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
15% {
rework: translate(1.003478261vw, 2.50608696vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
19.9% {
z-index: -1;
}
20% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
25% {
rework: translate(-3.51217391vw, 3.50608696vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
29.9% {
z-index: 2;
}
30% {
rework: translate(-5.01043478vw, 6.511304348vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
35% {
rework: translate(1.003478261vw, 2.50608696vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
39.9% {
z-index: -1;
}
40% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
45% {
rework: translate(-3.51217391vw, 3.50608696vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
49.9% {
z-index: 2;
}
50% {
rework: translate(-5.01043478vw, 6.511304348vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
55% {
rework: translate(1.003478261vw, 2.50608696vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
59.9% {
z-index: -1;
}
60% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
65% {
rework: translate(-3.51217391vw, 3.50608696vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
69.9% {
z-index: 2;
}
70% {
rework: translate(-5.01043478vw, 6.511304348vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
75% {
rework: translate(1.003478261vw, 2.50608696vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
79.9% {
z-index: -1;
}
80% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
85% {
rework: translate(-3.51217391vw, 3.50608696vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
89.9% {
z-index: 2;
}
90% {
rework: translate(-5.01043478vw, 6.511304348vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
95% {
rework: translate(1.003478261vw, 2.50608696vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
99.9% {
z-index: -1;
}
100% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
}
For those who take a look at the keyframes in that code, you’ll discover that the 0%
to 20%
keyframes are precisely the identical as 20%
to 40%
and so forth up by means of 100%
. Why I made a decision to repeat the keyframes 5 occasions infinitely as an alternative of simply repeating one set infinitely is a call misplaced to antiquity, like six years in the past in net time. We will additionally drop the period to 12 seconds (one-fifth of sixty) if we have been doing our due diligence.
I may thus delete every thing from 20%
on, immediately dropping the code right down to 36 strains. And sure, I understand good points like this are unlikely to be attainable on most websites, however this is step one for optimizing issues.
#moon1 {
animation: moon-one 12s infinite;
}
@keyframes moon-one {
0% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
5% {
rework: translate(-3.51217391vw, 3.50608696vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
9.9% {
z-index: 2;
}
10% {
rework: translate(-5.01043478vw, 6.511304348vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
15% {
rework: translate(1.003478261vw, 2.50608696vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
19.9% {
z-index: -1;
}
20% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
}
Now that we’ve gotten rid of 80% of the overwhelming bits, we are able to see that there are 5 most important keyframes and two extra ones that set the z-index
near the center and finish of the animation (these stop the moon from dropping behind the planet or coming out from behind the planet too early). We will change these 5 factors from 0%
, 5%
, 10%
, 15%
, and 20%
to 0%
, 25%
, 50%
, 75%
, and 100%
(and for the reason that 0%
and the previous 20%
are the identical, we are able to take away that one, too). Additionally, for the reason that 10%
keyframe above is switching to 50%
, the 9.9%
keyframe can transfer to 49.9%
, and the 19.9%
keyframe can swap to 99.9%
, giving us this:
#moon1 {
animation: moon-one 12s infinite;
}
@keyframes moon-one {
0%, 100% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
25% {
rework: translate(-3.51217391vw, 3.50608696vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
49.9% {
z-index: 2;
}
50% {
rework: translate(-5.01043478vw, 6.511304348vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
75% {
rework: translate(1.003478261vw, 2.50608696vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
99.9% {
z-index: -1;
}
}
Although I used to be very happy with myself for my math wrangling, numbers like -3.51217391vw
are actually, actually pointless. If a display screen was one thousand pixels vast, -3.51217391vw
can be 35.1217391
pixels. Nobody ever must go right down to the precision of a ten-millionth of a pixel. So, let’s spherical every thing to the tenth place (and if it’s a 0
, we’ll simply drop it). We will additionally skip z-index
within the 75%
and 25%
keyframes because it doesn’t change.
Right here’s the place that will get us within the code:
#moon1 {
animation: moon-one 12s infinite;
}
@keyframes moon-one {
0%, 100% {
rework: translate(0, 0) scale(1);
z-index: 2;
animation-timing-function: ease-in;
}
25% {
rework: translate(-3.5vw, 3.5vw) scale(1.5);
z-index: 2;
animation-timing-function: ease-out;
}
49.9% {
z-index: 2;
}
50% {
rework: translate(-5vw, 6.5vw) scale(1);
z-index: -1;
animation-timing-function: ease-in;
}
75% {
rework: translate(1vw, 2.5vw) scale(0.25);
z-index: -1;
animation-timing-function: ease-out;
}
99.9% {
z-index: -1;
}
}
In spite of everything our modifications, the animation nonetheless seems fairly near what it was earlier than, solely means much less code:
One of many issues I don’t like about this animation is that the moon form of turns at its zenith when it crosses the planet. It could be a lot better if it traveled in a straight line from the higher proper to the decrease left. Nonetheless, we additionally want it to get a bit of bigger, as if the moon is coming nearer to us in its orbit. As a result of each translation and scaling have been accomplished within the rework
property, I can’t translate and scale the moon independently.
If we skip both one within the rework
property, it resets the one we skipped, so I’m pressured to guess the place the mid-point needs to be in order that I can set the dimensions I would like. A method I’ve solved this prior to now is so as to add a wrapping ingredient, then apply scale
to 1 ingredient and translate
to the opposite. Nonetheless, now that we now have particular person scale
and translate
properties, a greater means is to separate them from the rework
property and use them as separate properties. Separating out the interpretation and scaling shouldn’t change something, until the unique order they have been declared on the rework
property was completely different than the order of the singular properties.
#moon1 {
animation: moon-one 12s infinite;
}
@keyframes moon-one {
0%, 100% {
translate: 0 0;
scale: 1;
z-index: 2;
animation-timing-function: ease-in;
}
25% {
translate: -3.5vw 3.5vw;
z-index: 2;
animation-timing-function: ease-out;
}
49.9% {
z-index: 2;
}
50% {
translate: -5vw 6.5vw;
scale: 1;
z-index: -1;
animation-timing-function: ease-in;
}
75% {
translate: 1vw 2.5vw;
scale: 0.25;
animation-timing-function: ease-out;
}
99.9% {
z-index: -1;
}
}
Now that we are able to separate the scale
and translate
properties and use them independently, we are able to drop the translate
property within the 25%
and 75%
keyframes as a result of we don’t need them positioned exactly in that keyframe. We would like the browser’s interpolation to care for that for us in order that it interprets easily whereas scaling.
#moon1 {
animation: moon-one 12s infinite;
}
@keyframes moon-one {
0%, 100% {
translate: 0 0;
scale: 1;
z-index: 2;
animation-timing-function: ease-in;
}
25% {
scale: 1.5;
animation-timing-function: ease-out;
}
49.9% {
z-index: 2;
}
50% {
translate: -5vw 6.5vw;
scale: 1;
z-index: -1;
animation-timing-function: ease-in;
}
75% {
scale: 0.25;
animation-timing-function: ease-out;
}
99.9% {
z-index: -1;
}
}
Lastly, these completely different timing capabilities don’t make plenty of sense anymore as a result of we’ve received the browser working for us, and if we use an ease-in-out
timing perform on every thing, then it ought to do precisely what we would like.
#moon1 {
animation: moon-one 12s infinite ease-in-out;
}
@keyframes moon-one {
0%, 100% {
translate: 0 0;
scale: 1;
z-index: 2;
}
25% {
scale: 1.5;
}
49.9% {
z-index: 2;
}
50% {
translate: -5vw 6.5vw;
scale: 1;
z-index: -1;
}
75% {
scale: 0.25;
}
99.9% {
z-index: -1;
}
}
And there you go: 141 strains down to twenty-eight, and I feel the animation seems even higher than earlier than. It would definitely be simpler to keep up, that’s for positive.
However what do you assume? Was there an optimization step I missed? Let me know within the feedback.
Orbital Mechanics (or How I Optimized a CSS Keyframes Animation) initially printed on CSS-Methods, which is a part of the DigitalOcean household. You need to get the publication.
Subscribe to MarketingSolution.
Receive web development discounts & web design tutorials.
Now! Lets GROW Together!