I'm migrating to web development and wanted to learn CSS animations better. I was playing Prey last night and realized the "throbber" on the elevator screen would be interesting to reimplement. For anyone not familar with the game, it can be seen briefly here (although that's not required for the review).
Here's the end result as a snippet:
.throbber-wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
justify-items: center;
align-items: center;
background-color: #2eb9e8;
width: 10em;
height: 10em;
}
.throbber-wrapper > div {
display: inline-block;
background-color: #93e2ff;
// For the sake of the animation so it starts without full boxes waiting to be animated.
width: 0;
height: 0;
opacity: 0;
animation: cellShrink 1000ms infinite;
}
@keyframes cellShrink {
0% {
width: 100%;
height: 100%;
opacity: 100%;
}
100% {
width: 10%;
height: 10%;
opacity: 10%;
}
}
.throbber-wrapper .b2 {
animation-delay: 62.5ms;
}
.throbber-wrapper .b3 {
animation-delay: 125ms;
}
.throbber-wrapper .b4 {
animation-delay: 187.5ms;
}
.throbber-wrapper .b8 {
animation-delay: 250ms;
}
.throbber-wrapper .b7 {
animation-delay: 312.5ms;
}
.throbber-wrapper .b6 {
animation-delay: 375ms;
}
.throbber-wrapper .b5 {
animation-delay: 437.5ms;
}
.throbber-wrapper .b9 {
animation-delay: 500ms;
}
.throbber-wrapper .b10 {
animation-delay: 562.5ms;
}
.throbber-wrapper .b11 {
animation-delay: 625ms;
}
.throbber-wrapper .b12 {
animation-delay: 687.5ms;
}
.throbber-wrapper .b16 {
animation-delay: 750ms;
}
.throbber-wrapper .b15 {
animation-delay: 812.5ms;
}
.throbber-wrapper .b14 {
animation-delay: 875ms;
}
.throbber-wrapper .b13 {
animation-delay: 937.5ms;
}
<div class="throbber-wrapper">
<div class="b1"></div>
<div class="b2"></div>
<div class="b3"></div>
<div class="b4"></div>
<div class="b5"></div>
<div class="b6"></div>
<div class="b7"></div>
<div class="b8"></div>
<div class="b9"></div>
<div class="b10"></div>
<div class="b11"></div>
<div class="b12"></div>
<div class="b13"></div>
<div class="b14"></div>
<div class="b15"></div>
<div class="b16"></div>
</div>
The color isn't perfect, but that's not my main concern. The main challenge when writing this was getting the timing of the squares right and written in a sane way (I think I only achieved the first goal there). A full cycle is one second, divided by 16 cells gives 62.5ms, so I decided to delay the animation of each cell by 62.5ms longer than the previous cell. That unfortunately meant manually IDing each cell, and manually writing delays for each cell. I was able to reduce the duplication a bit using SCSS nesting, but it's still atrocious.
What I'd like help with:
- This code has a disgusting amount of duplication. I would like to know about any tricks that can neaten it up.
- Any other CSS, SCSS, or even HTML tricks that can help make this code cleaner.
HTML (this is a component, not a full page):
<div class="throbber-wrapper">
<div class="b1"></div>
<div class="b2"></div>
<div class="b3"></div>
<div class="b4"></div>
<div class="b5"></div>
<div class="b6"></div>
<div class="b7"></div>
<div class="b8"></div>
<div class="b9"></div>
<div class="b10"></div>
<div class="b11"></div>
<div class="b12"></div>
<div class="b13"></div>
<div class="b14"></div>
<div class="b15"></div>
<div class="b16"></div>
</div>
SCSS:
.throbber-wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
justify-items: center;
align-items: center;
background-color: #2eb9e8;
width: 10em;
height: 10em;
}
.throbber-wrapper > div {
display: inline-block;
background-color: #93e2ff;
// For the sake of the animation so it starts without full boxes waiting to be animated.
width: 0;
height: 0;
opacity: 0;
animation: cellShrink 1000ms infinite;
}
@keyframes cellShrink {
0% {
width: 100%;
height: 100%;
opacity: 100%;
}
100% {
width: 10%;
height: 10%;
opacity: 10%;
}
}
.throbber-wrapper {
& .b2 {
animation-delay: 62.5ms;
}
& .b3 {
animation-delay: 125ms;
}
& .b4 {
animation-delay: 187.5ms;
}
& .b8 {
animation-delay: 250ms;
}
& .b7 {
animation-delay: 312.5ms;
}
& .b6 {
animation-delay: 375ms;
}
& .b5 {
animation-delay: 437.5ms;
}
& .b9 {
animation-delay: 500ms;
}
& .b10 {
animation-delay: 562.5ms;
}
& .b11 {
animation-delay: 625ms;
}
& .b12 {
animation-delay: 687.5ms;
}
& .b16 {
animation-delay: 750ms;
}
& .b15 {
animation-delay: 812.5ms;
}
& .b14 {
animation-delay: 875ms;
}
& .b13 {
animation-delay: 937.5ms;
}
}