I not too long ago up to date my portfolio at johnrhea.com. (If you happen to’re trying so as to add a CSS or front-end engineer with storytelling and animation abilities to your group, I’m your man.) I appreciated the look of a sequence of planets I’d created for one more private undertaking and determined to reuse them on my new website. 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 website, solely altering the items (em
items to viewport items utilizing some difficult math that I used to be very, very happy with) in order that they might scale correctly as a result of I’m… environment friendly with my time. Nonetheless, on cell, the planet would transfer up a number of pixels and down a number of pixels because the moons orbited round it. I suspected the plopped-in animation was the offender (it wasn’t, however at the least I acquired 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 traces, 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;
}
}
If you happen to 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 via 100%
. Why I made a decision to repeat the keyframes 5 instances infinitely as a substitute of simply repeating one set infinitely is a call misplaced to antiquity, like six years in the past in net time. We are able to additionally drop the length to 12 seconds (one-fifth of sixty) if we had been doing our due diligence.
I might thus delete the whole lot from 20%
on, immediately dropping the code right down to 36 traces. And sure, I understand positive aspects 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 essential 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 are able to change these 5 factors from 0%
, 5%
, 10%
, 15%
, and 20%
to 0%
, 25%
, 50%
, 75%
, and 100%
(and because the 0%
and the previous 20%
are the identical, we are able to take away that one, too). Additionally, because the 10%
keyframe above is switching to 50%
, the 9.9%
keyframe can transfer to 49.9%
, and the 19.9%
keyframe can change 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 was one thousand pixels extensive, -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 the whole lot to the tenth place (and if it’s a 0
, we’ll simply drop it). We are able to 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 will be significantly 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 had been finished 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 must be in order that I can set the dimensions I would like. A method I’ve solved this up to now is so as to add a wrapping component, then apply scale
to at least one component and translate
to the opposite. Nonetheless, now that now we 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 had been declared on the rework
property was totally 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 wish the browser’s interpolation to deal with 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 totally different timing features don’t make numerous sense anymore as a result of we’ve acquired the browser working for us, and if we use an ease-in-out
timing operate on the whole lot, then it ought to do precisely what we wish.
#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 traces 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 certain.
However what do you suppose? Was there an optimization step I missed? Let me know within the feedback.