25 CSS Spinners 08 / 25

Morph Square-to-Circle Spinner

A hollow square morphs fluidly through four asymmetric border-radius stages into a perfect circle and back, while simultaneously rotating — a classic CSS shape-morphing technique.

Pure CSS MIT licensed
Live Demo Open in tab

This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.

Open in playground

The code

<div class="sp-08">
  <div class="sp-08__outer">
    <div class="sp-08__track"></div>
    <div class="sp-08__shape"></div>
  </div>
</div>
.sp-08,.sp-08 *,.sp-08 *::before,.sp-08 *::after{box-sizing:border-box;margin:0;padding:0}
.sp-08{
  --bg:#0e0e12;
  --c:#ff9100;
  --glow:rgba(255,145,0,0.4);
  display:flex;
  align-items:center;
  justify-content:center;
  min-height:100vh;
  background:var(--bg);
}
.sp-08__shape{
  width:60px;
  height:60px;
  background:transparent;
  border:4px solid var(--c);
  filter:drop-shadow(0 0 8px var(--glow));
  animation:sp-08-morph 2s ease-in-out infinite, sp-08-spin 2s linear infinite;
}
@keyframes sp-08-morph{
  0%,100%{border-radius:4px;transform:rotate(0deg) scale(1)}
  25%{border-radius:50% 4px 50% 4px}
  50%{border-radius:50%;transform:rotate(180deg) scale(1.15)}
  75%{border-radius:4px 50% 4px 50%}
}
@keyframes sp-08-spin{
  0%{transform:rotate(0deg)}
  100%{transform:rotate(360deg)}
}
.sp-08__outer{
  position:relative;
  width:80px;
  height:80px;
  display:flex;
  align-items:center;
  justify-content:center;
}
.sp-08__track{
  position:absolute;
  inset:0;
  border-radius:50%;
  border:1px solid rgba(255,145,0,0.1);
}
@media (prefers-reduced-motion: reduce){
  .sp-08__shape{animation:none;border-radius:8px}
}

How this works

A single element uses two simultaneous animations: sp-08-morph drives the border-radius through four stages (sharp square → two-corner pill → circle → opposing two-corner pill → back), while sp-08-spin rotates the element 360° over the same period. Because both share the same 2s duration, the morph stages align with compass-point rotations, making the shape appear to tumble.

The element is otherwise a transparent rectangle with a coloured border and a filter:drop-shadow glow, so the shape outline is the primary visual. No child elements are needed — all motion is driven by the single div's transform and border-radius keyframes.

Customize

  • Change the shape at each morph stage by editing the four border-radius keyframe values — try a star-like 40% 60% 60% 40% / 60% 30% 70% 40% for organic forms.
  • Make the shape solid by replacing border with background:var(--c) and removing the border declarations.
  • Add a second counter-rotating copy at 50% opacity for a yin-yang-like interference pattern.
  • Set animation-timing-function:steps(4,end) to snap between shapes for a retro, frame-by-frame feel.
  • Reduce the element size to 40px for a compact inline spinner that fits in button labels.

Watch out for

  • Two simultaneous animation references on a single element in the CSS shorthand (animation: a 2s ..., b 2s ...) must share timing values carefully — any mismatch causes the morph and spin to drift out of sync.
  • filter:drop-shadow repaints on every frame during a morph since the painted shape changes — box-shadow is cheaper but only follows the border-box, not the morphed outline.
  • border-radius animation is interpolated by the CSS engine which can look jerky at large step changes; keep adjacent keyframe values close (within 20–30%) for smooth transitions.

Browser support

ChromeSafariFirefoxEdge
60+ 12+ 60+ 60+

Multi-value border-radius animation is well-supported across all modern engines.

Search CodeFronts

Loading…