Animate with clip-path
Animate clip-path: inset() for tabs, sliders and wipes: no layout.
Emil Kowalski@emilkowalskiThe Magic of Clip Path
Emil Kowalski@emilkowalskiToggle your theme using clip-path
Emil Kowalski@emilkowalskiA mix of clip path and CSS transitions
Emil KowalskiThe Magic of Clip Pathclip-path: inset(0px 75% 0px 0% round 17px);
From emil-design-eng and his clip-path article.
Tabs: clipped copy
Click a tab in slow motion; watch the label color.
Pill + color fadeBad
transition: color, transformClipped duplicateGood
clip-path: inset(0 75% 0 0% round 17px)<div class="tabs">
<div class="list">…buttons…</div>
<div class="list active" aria-hidden="true">…same labels…</div>
</div>
.list.active {
position: absolute; inset: 0;
background: var(--accent); color: var(--accent-ink);
pointer-events: none;
clip-path: inset(0 75% 0 0% round 17px);
transition: clip-path 250ms var(--ease-out);
}
const left = (i * 100) / n, right = ((n - 1 - i) * 100) / n;
active.style.clipPath = `inset(0 ${right}% 0 ${left}% round 17px)`;
Comparison slider
Drag either divider; watch the left text rewrap.
Resize the top layerBad
After
Revenue grew 18% after the pricing change
Before
Revenue grew 18% after the pricing change
width: 50%Clip the top layerGood
After
Revenue grew 18% after the pricing change
Before
Revenue grew 18% after the pricing change
clip-path: inset(0 50% 0 0).before {
position: absolute; inset: 0;
clip-path: inset(0 calc(100% - var(--pos)) 0 0);
}
slider.addEventListener("pointerdown", (e) => {
slider.setPointerCapture(e.pointerId);
move(e);
});
slider.addEventListener("pointermove", (e) => {
if (slider.hasPointerCapture(e.pointerId)) move(e);
});
function move(e) {
const r = slider.getBoundingClientRect();
const pct = Math.min(100, Math.max(0, ((e.clientX - r.left) / r.width) * 100));
slider.style.setProperty("--pos", `${pct}%`);
}
Theme wipe
Press a toggle, then press again mid-wipe.
Transition the colorsBad
Invoices3 due
- Acme Co$2,400
- Globex$980
- Initech$1,150
transition: all 300ms easeClip a themed copyGood
Invoices3 due
- Acme Co$2,400
- Globex$980
- Initech$1,150
clip-path: circle(r at x y).wipe {
position: absolute; inset: 0;
transition: clip-path 300ms var(--ease-in-out);
}
const r = Math.hypot(Math.max(x, w - x), Math.max(y, h - y));
wipe.style.clipPath = `circle(${r}px at ${x}px ${y}px)`;
wipe.addEventListener("transitionend", () => {
base.dataset.theme = next;
resetWipe();
});
Why it matters, pros and cons
Why it matters
A clip only picks which pixels paint: nothing reflows, color flips at the edge.
Pros
- No layout shift, no text rewrap.
- Color changes at the edge, one curve.
- A plain transition, so it retargets mid-flight.
Cons
- Duplicate DOM: hide the copy from assistive tech.
- Clips shadows and focus rings outside the box.
inset()tocircle()jumps; keep one shape function.