I am trying to create this loading animation in HTML and CSS using only CSS to animate it but I can't get the timing down.
Any tips on how I can get that to work?
<div style="display: flex; flex-direction: row; gap: 50px;">
<div style="height:100px;width:100px; background-color: #ccc">
<div class="square"></div>
</div>
<div style="height:100px;width:100px;border: 1px solid white; position: relative;">
<div id="squareToReveal-1" class="squareToReveal">1</div>
<div id="squareToReveal-2" class="squareToReveal">2</div>
<div id="squareToReveal-3" class="squareToReveal">3</div>
<div id="squareToReveal-4" class="squareToReveal">4</div>
</div>
</div>
body {
background-color: #1E2226;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.square {
width: 50px;
height: 50px;
background-color: white;
position: relative;
animation-name: moveSquare;
animation-duration: 2s;
animation-iteration-count: infinite;
}
@keyframes moveSquare {
0% {top: 0; left: 0}
25% {top: 0; left: 50%;}
50% {top: 50%; left: 50%;}
75% {top: 50%; left: 0px;}
100% {top: 0px; left: 0px;}
}
.squareToReveal {
width: 50px;
height: 50px;
background-color: #ccc;
opacity: 0;
position: absolute;
animation-name: revealSquare;
animation-duration: 2s;
animation-iteration-count: infinite;
}
#squareToReveal-1 {
top: 0;
left: 0;
animation-delay: 0;
}
#squareToReveal-2 {
top: 0;
left: 50%;
animation-delay: 0.5s;
}
#squareToReveal-3 {
top: 50%;
left: 50%;
animation-delay: 1s;
}
#squareToReveal-4 {
top: 50%;
left: 0;
animation-delay: 1.5s;
}
@keyframes revealSquare {
0% {opacity: 0;}
25% {opacity: 1;}
75% {opacity: 1;}
100% {opacity: 0;}
}
You can apply animation-timing-function: steps(1);
and break the "tiles" animation into the required frames. In fact, we have 8 frames (sorry for the photo quality):
body {
background-color: #1E2226;
display: grid;
place-items: center;
height: 100vh;
margin: 0;
}
.loading {
--size: 100px;
--duration: 2s;
position: relative;
width: var(--size);
height: var(--size);
display: flex;
}
.loading:before {
content: '';
position: absolute;
background-color: gray;
inset: 0;
animation: tile calc( var(--duration) * 2 ) steps(1) infinite;
}
.loading:after {
content: '';
width: calc(var(--size) / 2);
height: calc(var(--size) / 2);
background-color: #fff;
animation: move var(--duration) linear infinite;
}
@keyframes move {
25% {
transform: translate(100%, 0);
}
50% {
transform: translate(100%, 100%);
}
75% {
transform: translate(0, 100%);
}
}
@keyframes tile {
0% {
clip-path: polygon(0 0, 50% 0, 50% 50%, 0 50%);
}
12.5% {
clip-path: polygon(0 0, 100% 0, 100% 50%, 0 50%);
}
25% {
clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 100%, 50% 50%, 0 50%);
}
37.5% {
clip-path: unset;
}
50% {
clip-path: polygon(50% 0, 100% 0, 100% 100%, 0 100%, 0% 50%, 50% 50%);
}
62.5% {
clip-path: polygon(0 50%, 100% 50%, 100% 100%, 0% 100%);
}
75% {
clip-path: polygon(0 50%, 50% 50%, 50% 100%, 0% 100%);
}
87.5% {
clip-path: polygon(0 0);
}
}
<div class="loading"></div>