Four isometric plates in a stack lift one after another in a soft ripple while an accent fill climbs to the top. A hairline SVG and CSS loading indicator on the 2:1 grid.
Also known as: isometric loading animation, stacked layers loader, hairline loader.
<div class="hln-tile-stack-loader" role="status" aria-label="Loading"> <svg viewBox="-110 -60 220 120" aria-hidden="true"><g transform="translate(0 12) scale(1.9)"><g class="hln-tile-stack-loader-tile" style="--d: 0s"><g><polygon points="-22,0 0,11 0,8.5 -22,-2.5"/><polygon points="22,0 0,11 0,8.5 22,-2.5"/><polygon points="0,-13.5 22,-2.5 0,8.5 -22,-2.5"/></g><polygon class="hln-tile-stack-loader-in" points="0,-8.5 12,-2.5 0,3.5 -12,-2.5"/></g><g class="hln-tile-stack-loader-tile" style="--d: 0.3s"><g><polygon points="-22,-7 0,4 0,1.5 -22,-9.5"/><polygon points="22,-7 0,4 0,1.5 22,-9.5"/><polygon points="0,-20.5 22,-9.5 0,1.5 -22,-9.5"/></g><polygon class="hln-tile-stack-loader-in" points="0,-15.5 12,-9.5 0,-3.5 -12,-9.5"/></g><g class="hln-tile-stack-loader-tile" style="--d: 0.6s"><g><polygon points="-22,-14 0,-3 0,-5.5 -22,-16.5"/><polygon points="22,-14 0,-3 0,-5.5 22,-16.5"/><polygon points="0,-27.5 22,-16.5 0,-5.5 -22,-16.5"/></g><polygon class="hln-tile-stack-loader-in" points="0,-22.5 12,-16.5 0,-10.5 -12,-16.5"/></g><g class="hln-tile-stack-loader-tile" style="--d: 0.9s"><g><polygon points="-22,-21 0,-10 0,-12.5 -22,-23.5"/><polygon points="22,-21 0,-10 0,-12.5 22,-23.5"/><polygon points="0,-34.5 22,-23.5 0,-12.5 -22,-23.5"/></g><polygon class="hln-tile-stack-loader-in" points="0,-29.5 12,-23.5 0,-17.5 -12,-23.5"/></g></g></svg> </div>
.hln-tile-stack-loader {
--c: var(--hln-color, #ff4f2e);
font-size: var(--hln-size, 16px);
position: relative;
display: grid;
place-items: center;
width: 22em;
height: 12em;
border-radius: 0.75em;
background: #f6f5f1;
overflow: hidden;
--u: 1px;
}
.hln-tile-stack-loader svg {
width: 100%;
height: 100%;
overflow: visible;
fill: #ffffff;
stroke: #1c1d21;
stroke-width: 1.25;
stroke-linejoin: round;
stroke-linecap: round;
}
.hln-tile-stack-loader svg * {
vector-effect: non-scaling-stroke;
}
.hln-tile-stack-loader .hln-tile-stack-loader-in {
stroke: #9a9ca3;
}
.hln-tile-stack-loader .hln-tile-stack-loader-tile {
animation: hln-tile-stack-loader-lift 3s var(--d) infinite;
}
.hln-tile-stack-loader .hln-tile-stack-loader-tile > g > polygon {
animation: hln-tile-stack-loader-fill 3s var(--d) infinite;
}
.hln-tile-stack-loader .hln-tile-stack-loader-tile > .hln-tile-stack-loader-in {
fill: none;
}
@keyframes hln-tile-stack-loader-lift {
0% { translate: 0 0; animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
10% { translate: 0 calc(-3.6 * var(--u)); animation-timing-function: ease-in-out; }
18% { translate: 0 calc(0.3 * var(--u)); animation-timing-function: ease-in-out; }
24%, 100% { translate: 0 0; }
}
@keyframes hln-tile-stack-loader-fill {
0% { fill: #ffffff; }
3%, 9% { fill: var(--c); }
16%, 100% { fill: #ffffff; }
}
@media (prefers-reduced-motion: reduce) {
.hln-tile-stack-loader * {
animation: none !important;
}
.hln-tile-stack-loader .hln-tile-stack-loader-tile:last-child > g > polygon:last-child { fill: var(--c); }
}
@media (prefers-reduced-motion: reduce) {
.hln-tile-stack-loader, .hln-tile-stack-loader *, .hln-tile-stack-loader::before, .hln-tile-stack-loader::after, .hln-tile-stack-loader *::before, .hln-tile-stack-loader *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--hln-color on the element or a parent.
Currently previewing #3b82f6.--hln-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.