w3tweaks.com · CSS Tutorial

CSS clip-path

Create any shape. Animate reveals. No SVG, no extra HTML.

Tab 1

Shape Gallery — Click to Get the Code

Click any shape to see it previewed and get the copy-paste CSS. All shapes use the same element — just clip-path changes.

Preview
circle(50%)
Generated CSS
.element {
  clip-path: circle(50%);
  transition: clip-path .3s ease;
}

/* For hover effects, animate to another shape
   with the SAME vertex count — see the
   Animation Patterns tab for working examples. */
Coordinate system: 0% 0% = top-left corner. 100% 0% = top-right. 100% 100% = bottom-right. 50% 50% = center. Points connect clockwise to form the visible shape.
Key rule — animation requires compatible shapes: You can only animate between polygon() to polygon() shapes with the same number of vertices. A 4-point polygon can animate to another 4-point polygon. A circle() cannot directly animate to a polygon(). To animate between incompatible shapes, convert both to polygon() and pad with duplicate vertices.
Tab 2

4 Animation Patterns — Click to Play

All transitions are CSS-only. Click any demo to replay the animation. Works with transition, @keyframes, and hover.

← Wipe Reveal (left to right)
/* Start: fully hidden */
.el { clip-path: polygon(0 0,0 0,0 100%,0 100%); }
/* End: fully visible */
.el.visible { clip-path: polygon(0 0,100% 0,100% 100%,0 100%); }
.el { transition: clip-path .8s ease; }

Points 2 and 4 expand from 0% to 100% — same vertex count so the browser interpolates smoothly.

◉ Circle Expand Reveal
/* Hidden */
.el { clip-path: circle(0% at 50% 50%); }
/* Revealed */
.el.open { clip-path: circle(150% at 50% 50%); }
.el { transition: clip-path .7s ease; }

Perfect for page transitions — a circle expands from the click point. Change at X% Y% to expand from any origin.

⬟ Polygon Morph
/* Pentagon → Diamond (5 pts → 5 pts) */
.el { clip-path: polygon(
  50% 0%,100% 38%,82% 100%,18% 100%,0% 38%
)
; }
.el:hover { clip-path: polygon(
  50% 0%,100% 50%,50% 100%,0% 50%,0% 50%
)
; }

Both shapes have 5 vertices — the browser morphs between them smoothly. Duplicate the last point to balance vertex counts.

↓ Scroll Reveal (CSS-only with :has)
/* Progressive reveal with IntersectionObserver */
.reveal { clip-path: inset(0 100% 0 0); }
.reveal.visible { clip-path: inset(0 0% 0 0); }
@media (prefers-reduced-motion: reduce) {
  .reveal { clip-path: none; }
}

The right inset collapses from 100% to 0% — creating a wipe. Always wrap in prefers-reduced-motion.

Always respect prefers-reduced-motion: clip-path animations can be visually intense. Wrap them in @media (prefers-reduced-motion: reduce) to set clip-path: none or skip the transition for users who have motion sensitivity settings enabled.
Tab 3

Real-World Use Cases

Every pattern below is pure CSS — no SVG files, no extra HTML elements, no image masks.

📐 Diagonal Hero Section
Hero with diagonal cut
Content section below
.hero {
  clip-path: polygon(0 0, 100% 0, 100% 75%, 0 100%);
}

The bottom-right corner is at 75% while the bottom-left is at 100%. Swap values for opposite diagonal.

👤 Custom Avatar Shapes
😊
🎯
🛡️
.circle { clip-path: circle(50%); }
.hexagon { clip-path: polygon(50% 0%,100% 25%,100% 75%,50% 100%,0% 75%,0% 25%); }
.diamond { clip-path: polygon(50% 0%,100% 50%,50% 100%,0% 50%); }

Works on <img> elements directly. No wrapper div needed. Shapes are crisp at any resolution.

🏷️ Notched Badges & Tags
NEW SALE HOT
.tag {
  clip-path: polygon(
    0 0, 100% 0,
    calc(100% - 10px) 50%,
    100% 100%, 0 100%
  )
;
}

calc() inside polygon() creates the pointed notch without knowing the element's width.

〰️ Section Divider
Primary section
Secondary section beneath
/* Section with diagonal bottom */
.section {
  clip-path: polygon(0 0, 100% 0, 100% 60%, 0 100%);
}
.next-section { margin-top: -40px; }

A negative margin-top on the following section pulls it under the clipped area for a seamless overlap.

✦ Layered ::before Decoration
Card with clipped ::before glow
.card { position: relative; }
.card::before {
  content: "";
  position: absolute; inset: -8px;
  clip-path: polygon(0 20px,20px 0,100% 0,...);
  z-index: -1;
}

clip-path on ::before creates decorative shapes behind elements — no extra HTML, no SVG files needed.

◻️ inset() — Animatable Corners
0px
12px
50%
shrunk
/* inset(top right bottom left round radius) */
clip-path: inset(0 0 0 0 round 16px); ← rounded
clip-path: inset(10% 5% round 8px); ← shrunk

Unlike border-radius, inset() clips the element — allowing smooth animation to other clip-path shapes and working on images without a wrapper.

✨ shape() — The New CSS Function (Baseline Feb 2026)
NEW

shape() brings SVG path commands directly into CSS — move, line, curve, arc — with CSS units like px, %, and rem. It became Baseline (all major browsers) in February 2026. Unlike path(), it supports responsive CSS units.

/* shape() — SVG-like path commands with CSS units */
clip-path: shape(
  from 0% 0%,
  line to 100% 0%,
  line to 100% 70%,
  curve to 0% 100% via 50% 85%, ← bezier curve
  close
)
;
Read the tutorial