</>
cssgenerators.dev
Star on GitHub

CSS clip-path: Shapes, Creative Effects and Hover Animations

A complete guide to CSS clip-path: every shape function, polygon recipes for triangles, hexagons and stars, GPU-composited hover animations, and live browser demos you can see right here.

By Dinno SAS · · 11 min read

Of all the CSS properties that shipped in the past decade, clip-path is the one that most consistently surprises developers with what it can do. A single property line turns a plain rectangle into a hexagon, a star, a diagonal hero section, or a reveal animation that makes a gradient seem to slide in from the side. And unlike SVG-based approaches, everything stays in CSS — no extra markup, no image files.

This guide covers every shape function, gives you polygon recipes you can copy directly, and shows you six live demos running in your browser right now — no CodePen, no screenshot.

What shape functions does clip-path support?

The CSS clip-path property accepts five shape functions from the CSS Shapes specification, plus a reference to an SVG <clipPath> element. Each function defines the clipping region differently.

inset()
circle()
ellipse()
polygon()

What does inset() do?

inset(top right bottom left) crops the element from each edge inward, like padding in reverse. You can also pass a single value to crop equally on all sides, or use the round keyword to add border-radius to the cropped rectangle:

/* Crop 10px on all sides */
clip-path: inset(10px);

/* Different values per side */
clip-path: inset(10px 20px 10px 0);

/* Rounded crop — great for "pill" clipping */
clip-path: inset(0 round 50px);

/* Asymmetric rounded crop */
clip-path: inset(10px round 8px 32px 8px 32px);

inset() is the most practical function for masking images and creating slide-in reveal animations, because its values are straightforward to interpolate.

What does circle() do?

circle(radius at x y) clips the element to a circle. The radius can be a length, a percentage of the element's diagonal, or the keywords closest-side / farthest-side. The position defaults to the element center:

/* Circle from the center, radius 40px */
clip-path: circle(40px);

/* Off-center circle */
clip-path: circle(60px at 20% 80%);

/* Fill the shortest dimension */
clip-path: circle(closest-side);

What does ellipse() do?

ellipse(rx ry at x y) is the two-radius version of circle(). It accepts horizontal and vertical radii independently:

clip-path: ellipse(55% 40% at 50% 50%);

/* Wide ellipse crop at the bottom — useful for wave-like section separators */
clip-path: ellipse(100% 60% at 50% 100%);

What does polygon() do?

polygon(x1 y1, x2 y2, ...) is the most powerful function. You define an arbitrary number of vertices as x/y pairs (percentages, px, or any length unit), and the browser draws the shape by connecting them in order. Every shape you see below is a polygon().

What polygon shapes can you make?

Here are six ready-to-copy polygon recipes for the most common shapes developers reach for:

Hexagon
Star
Arrow
Triangle
Diamond
Chevron
/* Hexagon */
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);

/* 5-point star */
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%,
                   50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);

/* Arrow / chevron pointing right */
clip-path: polygon(0 25%, 60% 25%, 60% 0%, 100% 50%, 60% 100%, 60% 75%, 0 75%);

/* Triangle pointing up */
clip-path: polygon(50% 0%, 100% 100%, 0% 100%);

/* Diamond */
clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);

/* Angled chevron tab */
clip-path: polygon(0 0, 85% 0, 100% 50%, 85% 100%, 0 100%);

Tip: Our CSS Clip Path Generator lets you drag polygon points visually and copy the result — no mental geometry required.

How do you use clip-path for hero sections?

One of the most popular applications is cutting a diagonal or wave edge at the bottom of a full-width section, replacing the flat horizontal line with something more dynamic. The technique requires only a polygon() with four points where the bottom two are at different heights:

Hero section with diagonal cut
/* The section element */
.hero {
  clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%);
  /* Bottom-right corner stays at 80% height; bottom-left drops to 100% */
}

/* Reverse diagonal */
.hero-reverse {
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 80%);
}

/* Both bottom corners angled inward — chevron bottom */
.hero-chevron {
  clip-path: polygon(0 0, 100% 0, 100% 80%, 50% 100%, 0 80%);
}

The key detail: because clip-path clips the element including its shadow and outline, you need the section below it to overlap slightly (negative margin-top or absolute positioning) to avoid a gap between sections.

How do you animate clip-path on hover?

clip-path is fully animatable via CSS transitions and @keyframes. The browser interpolates between two clip values smoothly as long as both use the same function. This enables some of the most fluid reveal effects in CSS today.

Horizontal reveal with inset()

The most practical reveal animation: inset(0 100% 0 0) hides the element entirely by collapsing the right edge to the left. On hover, it opens to inset(0 0% 0 0) — fully visible. Hover the gradient below:

Hover to reveal →
inset() reveal
.reveal-element {
  clip-path: inset(0 100% 0 0); /* Fully hidden */
  transition: clip-path 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.reveal-element:hover,
.reveal-element.is-visible {
  clip-path: inset(0 0% 0 0); /* Fully visible */
}

Swap the axes for a vertical reveal: inset(100% 0 0 0)inset(0 0 0 0). Use this on scroll-triggered animations (add the is-visible class via IntersectionObserver).

Polygon morphing — the same number of points rule

CSS can transition between any two polygon() values — but only if they have the same number of coordinate pairs. The browser interpolates each point independently, so a 10-point star can morph to a 10-point "circle approximation" (a polygon with 10 evenly-spaced vertices around a center). If the point counts differ, the transition snaps immediately with no interpolation.

Hover the shape below to see a 10-point star morph into a hexagonal form:

Hover to morph
.morph-shape {
  /* 10-point star */
  clip-path: polygon(
    50% 0%, 61% 35%, 98% 35%, 68% 57%,
    79% 91%, 50% 70%, 21% 91%, 32% 57%,
    2% 35%, 39% 35%
  );
  transition: clip-path 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}

.morph-shape:hover {
  /* Same 10 points, different positions */
  clip-path: polygon(
    50% 0%, 100% 19%, 100% 81%, 50% 100%,
    0% 81%, 0% 19%, 50% 0%, 100% 19%,
    100% 81%, 50% 100%
  );
}

What are practical use cases for clip-path?

Angled badges and labels

A slanted clip at one end of a rectangle creates a badge that looks designed rather than generic. The polygon cuts the right edge at an angle while the left stays flush:

POPULAR
Angled badge
NEW
Reverse angle
/* Right side angled inward */
.badge {
  clip-path: polygon(0 0, 100% 0, 92% 100%, 0 100%);
}

/* Left side angled inward */
.badge-reverse {
  clip-path: polygon(8% 0, 100% 0, 100% 100%, 0 100%);
}

Hexagonal avatars

Profile pictures clipped to hexagons are common in gaming UIs and dashboards. The key is keeping the element square before clipping — the hexagon polygon uses percentage values that will distort on a rectangle:

DS
Hex avatar
MK
Circle avatar
.avatar-hex {
  width: 90px;
  height: 90px; /* Must be square */
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
  overflow: hidden;
}

.avatar-hex img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

What is the difference between clip-path and mask-image?

Both properties hide parts of an element, but they operate differently:

  • clip-path uses geometric shapes. The result is binary — pixels are either fully visible or fully hidden. The edges are always hard (anti-aliased, but not soft).
  • mask-image uses an image, gradient, or SVG as a mask. The alpha channel of the mask controls the opacity of the element at each pixel, so you can have smooth fades, gradual reveals, and irregular soft edges.

In practice:

  • Use clip-path for geometric shapes, diagonal cuts, hover reveals, and anything that needs to animate smoothly.
  • Use mask-image for feathered edges, complex image-based cutouts, and blending an element into its background.
/* clip-path — hard geometric edge */
.element {
  clip-path: polygon(0 0, 100% 0, 100% 80%, 0 100%);
}

/* mask-image — soft faded edge using a gradient */
.element {
  mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent 100%);
}

Is clip-path good for animation performance?

Yes — and this is a meaningful advantage over alternatives. When you animate clip-path, modern browsers handle it on the GPU compositor thread. That means the CPU does not need to repaint the element on every frame. The animation runs at 60fps even on mid-range hardware.

Compare this to alternatives that trigger layout or paint:

  • width/height — triggers layout recalculation on every frame. Avoid for animations.
  • border-radius — triggers paint on complex elements. Better than layout, but still more expensive than compositor-only.
  • clip-path — compositor-only. The browser can skip layout and paint entirely and animate directly on the GPU.
  • transform + overflow:hidden — comparable performance, but overflow:hidden creates a new stacking context and affects child positioning.

The practical rule: for reveal animations and shape transitions, reach for clip-path first. For truly complex masks that cannot be expressed as polygons, mask-image with a CSS gradient is the next choice.

What is the browser support for clip-path?

The basic shape functions — inset(), circle(), ellipse(), and polygon() — work in all modern browsers and have done so since 2016. Global support is above 97%. No vendor prefix is required in 2026.

The path() function, which accepts an SVG path string as a clip shape, landed more recently: Chrome 88 (January 2021), Firefox 71, and Safari 13.1 (Spring 2020). If you need to support older Safari versions, verify on caniuse.com/css-clip-path.

/* Basic shapes — safe everywhere */
clip-path: polygon(0 0, 100% 0, 85% 100%, 0 100%);

/* path() — check browser support for your audience */
clip-path: path("M 0,0 L 100,0 Q 150,50 100,100 L 0,100 Z");

For the path() function specifically, use it as a progressive enhancement: define a polygon() fallback first, then override with path() for browsers that support it. Since clip-path is not part of a feature query that @supports handles cleanly for path() specifically, the simplest approach is to check if your minimum browser targets include Safari 13.1+.

Try it: build your own clip-path

Understanding polygon points is much easier with a visual editor. Drag the handles, see the polygon update in real time, and copy the CSS:

→ CSS Clip Path Generator → CSS Triangle Generator → CSS Arrow Generator