AI CSS Animations

Extruded Progress Slab

A progress bar as an isometric slab that extrudes along its ruled base in three springy steps to full, accent on top, then clears. Hairline SVG through a clip path, CSS translate.

Also known as: isometric progress bar, 3d progress bar css, hairline loader.

HTML

<div class="hln-progress-slab" role="status" aria-label="Loading, progress bar filling">
  <svg viewBox="-110 -60 220 120" aria-hidden="true"><g transform="translate(0 4) scale(1.6)"><defs><clipPath id="hln-progress-slab-clip"><polygon points="-41,80 -41,-18.5 -41,-22.5 -33,-26.5 -33,-80 200,-80 200,80"/></clipPath></defs><g><polygon points="-50,-17 30,23 30,21 -50,-19"/><polygon points="46,15 30,23 30,21 46,13"/><polygon points="-34,-27 46,13 30,21 -50,-19"/></g><line class="hln-progress-slab-in" x1="-43" y1="-17.5" x2="-45" y2="-16.5"/><line class="hln-progress-slab-in" x1="-34" y1="-13" x2="-36" y2="-12"/><line class="hln-progress-slab-in" x1="-25" y1="-8.5" x2="-27" y2="-7.5"/><line class="hln-progress-slab-in" x1="-16" y1="-4" x2="-18" y2="-3"/><line class="hln-progress-slab-in" x1="-7" y1="0.5" x2="-9" y2="1.5"/><line class="hln-progress-slab-in" x1="2" y1="5" x2="0" y2="6"/><line class="hln-progress-slab-in" x1="11" y1="9.5" x2="9" y2="10.5"/><line class="hln-progress-slab-in" x1="20" y1="14" x2="18" y2="15"/><line class="hln-progress-slab-in" x1="29" y1="18.5" x2="27" y2="19.5"/><g><polygon points="-47,-19.5 -43,-17.5 -43,-24.5 -47,-26.5"/><polygon points="-31,-23.5 -43,-17.5 -43,-24.5 -31,-30.5"/><polygon points="-35,-32.5 -31,-30.5 -43,-24.5 -47,-26.5"/></g><g clip-path="url(#hln-progress-slab-clip)"><g class="hln-progress-slab-fill"><g><polygon points="-113,-54.5 -41,-18.5 -41,-22.5 -113,-58.5"/><polygon points="-33,-22.5 -41,-18.5 -41,-22.5 -33,-26.5"/><polygon points="-105,-62.5 -33,-26.5 -41,-22.5 -113,-58.5"/></g></g></g><polyline fill="none" points="-41,-18.5 -41,-22.5 -33,-26.5"/></g></svg>
</div>

CSS

.hln-progress-slab {
  --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-progress-slab svg {
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: #ffffff;
  stroke: #1c1d21;
  stroke-width: 1.25;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.hln-progress-slab svg * {
  vector-effect: non-scaling-stroke;
}
.hln-progress-slab .hln-progress-slab-in {
  stroke: #9a9ca3;
}
.hln-progress-slab .hln-progress-slab-fill {
  animation: hln-progress-slab-fill 5.2s infinite;
}
.hln-progress-slab .hln-progress-slab-fill polygon:last-child {
  fill: var(--c);
}
@keyframes hln-progress-slab-fill {
  0% { translate: 0 0; opacity: 1; }
  6% { translate: 0 0; animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  13.7% { translate: calc(24.88 * var(--u)) calc(12.44 * var(--u)); animation-timing-function: ease-in-out; }
  17.2% { translate: calc(22.58 * var(--u)) calc(11.29 * var(--u)); animation-timing-function: ease-in-out; }
  20% { translate: calc(23.04 * var(--u)) calc(11.52 * var(--u)); }
  28% { translate: calc(23.04 * var(--u)) calc(11.52 * var(--u)); animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  35.7% { translate: calc(51.03 * var(--u)) calc(25.52 * var(--u)); animation-timing-function: ease-in-out; }
  39.2% { translate: calc(48.44 * var(--u)) calc(24.22 * var(--u)); animation-timing-function: ease-in-out; }
  42% { translate: calc(48.96 * var(--u)) calc(24.48 * var(--u)); }
  50% { translate: calc(48.96 * var(--u)) calc(24.48 * var(--u)); animation-timing-function: cubic-bezier(0.3, 0, 0.2, 1); }
  57.7% { translate: calc(73.84 * var(--u)) calc(36.92 * var(--u)); animation-timing-function: ease-in-out; }
  61.2% { translate: calc(71.54 * var(--u)) calc(35.77 * var(--u)); animation-timing-function: ease-in-out; }
  64% { translate: calc(72 * var(--u)) calc(36 * var(--u)); }
  84% { translate: calc(72 * var(--u)) calc(36 * var(--u)); opacity: 1; animation-timing-function: ease-in; }
  94%, 100% { translate: calc(72 * var(--u)) calc(36 * var(--u)); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .hln-progress-slab * {
    animation: none !important;
  }
  .hln-progress-slab .hln-progress-slab-fill { translate: calc(48.96 * var(--u)) calc(24.48 * var(--u)); }
}

@media (prefers-reduced-motion: reduce) {
  .hln-progress-slab, .hln-progress-slab *, .hln-progress-slab::before, .hln-progress-slab::after, .hln-progress-slab *::before, .hln-progress-slab *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

Customizing this snippet

  • Color: set --hln-color on the element or a parent. Currently previewing #3b82f6.
  • Base size: set --hln-size. Every other dimension is in em, so the whole thing scales together. Currently previewing 16px.
  • Speed: change the duration on the transition or animation shorthand. Staggered delays are relative, so they keep their rhythm.
  • Reduced motion: the rule at the end of the CSS turns the motion off for people who asked their OS for less of it. Keep it.

Similar hairline animations