3D equalizer
Pure CSSSeven real cuboids bouncing like an audio meter. Walls are squashed with scaleY and each lid rides down by the same amount, so nothing but transforms ever changes.
A 4×4 grid of two-sided tiles flipping in a diagonal wave.
Your edited version
::before and ::after, back to back, both with backface-visibility: hidden.animation-delay = (row + column) × step. In plain CSS you set --d per tile; in Sass a nested @for loop writes it.backface-visibilitydelay = (row + column) × stepSass nested @for<div class="scene">
<div class="tiles">
<i style="--d:0"></i><i style="--d:1"></i><i style="--d:2"></i><i style="--d:3"></i>
<i style="--d:1"></i><i style="--d:2"></i><i style="--d:3"></i><i style="--d:4"></i>
<i style="--d:2"></i><i style="--d:3"></i><i style="--d:4"></i><i style="--d:5"></i>
<i style="--d:3"></i><i style="--d:4"></i><i style="--d:5"></i><i style="--d:6"></i>
</div>
</div>
.scene {
perspective: 800px;
}
.tiles {
display: grid;
grid-template-columns: repeat(4, 48px);
gap: 8px;
transform-style: preserve-3d;
transform: rotateX(38deg) rotateZ(-8deg);
}
.tiles i {
position: relative;
height: 48px;
transform-style: preserve-3d;
animation: tile-flip 3.2s ease-in-out infinite;
animation-delay: calc(var(--d) * 0.13s); /* --d = row + column */
}
.tiles i::before,
.tiles i::after {
content: '';
position: absolute;
inset: 0;
border-radius: 8px;
backface-visibility: hidden;
}
.tiles i::before { background: #8b6cff; }
.tiles i::after { background: #2ee6d6; transform: rotateY(180deg); }
@keyframes tile-flip {
0%, 15% { transform: rotateY(0deg); }
45%, 65% { transform: rotateY(180deg) translateZ(-14px); }
95%, 100% { transform: rotateY(360deg); }
}
$cols: 4;
.d-tiles {
display: grid;
grid-template-columns: repeat($cols, 38px);
gap: 6px;
transform-style: preserve-3d;
transform: rotateX(38deg) rotateZ(-8deg);
i {
position: relative;
height: 38px;
transform-style: preserve-3d;
animation: d-tiles-flip 3.2s ease-in-out infinite;
// Two faces back to back; each hides when it turns away.
&::before,
&::after {
content: '';
position: absolute;
inset: 0;
border-radius: 8px;
backface-visibility: hidden;
}
&::before {
background: var(--accent);
}
&::after {
background: var(--accent-2);
transform: rotateY(180deg);
}
}
// delay = (row + column) × step → a diagonal wave
@for $row from 0 to $cols {
@for $col from 0 to $cols {
i:nth-child(#{$row * $cols + $col + 1}) {
animation-delay: ($row + $col) * 0.13s;
}
}
}
}
@keyframes d-tiles-flip {
0%,
15% {
transform: rotateY(0deg);
}
45%,
65% {
transform: rotateY(180deg) translateZ(-14px);
}
95%,
100% {
transform: rotateY(360deg);
}
}