body {
    margin: 0;
    height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: black;
}

.loader {
    --duration: 5s;
    font-size: 40px;
    width: 7em;
    height: 5em;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    position: relative;
}

/* balls */
.loader::before,
.loader::after {
    content: '';
    position: absolute;
    width: 1em;
    height: 1em;
    background-color: white;
    border-radius: 50%;
    bottom: 1em;
    animation: var(--duration) infinite;
    animation-name: jumpY, moveX, hideMe;
    animation-timing-function: cubic-bezier(0.4, 1.7, 0.5, 1.2), ease, ease;
}

.loader::before {left: 0; --direction: 1;}
.loader::after {left: 6em; --direction: -1;}

.loader::after {
    animation-delay: calc(var(--duration) / 2 * -1);
}

@keyframes jumpY {
    0%, 100% {bottom: 1em;}
    10% {bottom: 2em;}
    20% {bottom: 3em;}
    30% {bottom: 4em;}
    40% {bottom: 5em; animation-timing-function: ease;}
    50% {bottom: 1em;}
}

@keyframes moveX {
    0%, 100% {transform: translateX(0);}
    10% {transform: translateX(calc(1 * 1.5em * var(--direction)));}
    20% {transform: translateX(calc(2 * 1.5em * var(--direction)));}
    30% {transform: translateX(calc(3 * 1.5em * var(--direction)));}
    40%, 50% {transform: translateX(calc(4 * 1.5em * var(--direction)));}
}

@keyframes hideMe {
    50%, 100% {visibility: hidden;}
}

/* columns */
.loader span {
    width: 1em;
    height: calc(var(--n) * 1em);
    background-color: hsla(0, 0%, 75%);
    border-radius: 0.1em;
    animation: sort ease var(--duration) infinite;
}

@keyframes sort {
    0%, 40%, 100% {height: calc(var(--n) * 1em);}
    50%, 90% {height: calc((6 - var(--n)) * 1em);}
}

.loader span:nth-child(1) {--n: 1;}
.loader span:nth-child(2) {--n: 2;}
.loader span:nth-child(3) {--n: 3;}
.loader span:nth-child(4) {--n: 4;}
.loader span:nth-child(5) {--n: 5;}
