border-radius solves the rounded-rectangle case well, but real designs frequently need shapes it can't express at all ā triangles, hexagons, diagonal cuts, arbitrary custom silhouettes. clip-path is the tool built for exactly that.
1Basic Shapes: Concise Tools For Common Cases
For the most common non-rectangular shape needs, clip-path offers dedicated, concise functions rather than requiring a full polygon definition every time. circle(50%) clips an element to a circle centered by default (with an optional position argument for off-center circles). ellipse(rx ry) produces an oval. inset(top right bottom left) clips a rectangle pulled in from each edge independently ā genuinely different from padding, since it clips (hard-cuts) rather than adding internal space, useful for cropping an image to reveal only a specific inner region.
These basic shapes cover the majority of real-world non-rectangular clipping needs far more concisely than the equivalent polygon() would require.
2polygon(): Full Creative Control
polygon() takes a comma-separated list of x/y coordinate pairs, each defining one vertex of the clipping shape, connected in the order given to form the shape's outline. A diagonal-cut banner, for instance, might use polygon(0 0, 100% 0, 100% 80%, 0 100%) ā four points forming a rectangle whose bottom edge slopes from 100% height on the left down to 80% height on the right, producing a slanted-cut visual effect entirely through CSS, no image asset required.
This is the tool to reach for whenever a design calls for a shape basic functions can't express directly ā arrows, chevrons, hexagonal cards, star shapes, or any bespoke silhouette a designer has specified.
3Smooth Reveal Effects Through Shape Interpolation
Because a clip-path polygon is fundamentally a list of coordinate values, and CSS can interpolate between two lists of matching numeric values, transitioning clip-path between two polygon() definitions with the same number of points produces a smooth, genuinely morphing animation ā each vertex smoothly moves from its starting position to its ending position. This underlies a very common, visually striking pattern: a menu 'unfolding' from a corner, an image revealing itself with a wipe effect, or a shape smoothly transforming from one silhouette into a related one.
A practical detail worth remembering: for the smoothest results, keep the point count identical between the two polygon states (even if that means adding 'redundant' points to a simpler shape to match a more complex target shape's point count) ā mismatched point counts can produce unexpected or jarring interpolation behavior.
4Step-by-Step Breakdown
Cutting An Element Into A Custom Shape. border-radius rounds a rectangle's corners. clip-path does something more fundamental: it defines an arbitrary region and renders only the part of the element falling inside it, discarding everything outside ā cutting a rectangular element into a triangle, hexagon, circle, or any custom polygon shape entirely.
Basic Shapes: circle(), ellipse(), inset(). clip-path's basic shape functions cover the most common cases directly: circle(50%) clips to a circle, ellipse() to an oval, and inset() to a rectangle pulled in from each edge (useful for a rounded-rectangle crop with independent per-side insets) ā each far more concise than an equivalent polygon would be for these regular shapes.
Basic Shape Functions. What does clip-path: circle(50%) do to a square element?
- āIt rounds the corners slightly, similar to border-radius
- āIt clips the element to a perfect circle, discarding everything outside that circular region
- āIt has no visible effect on a square element
polygon() For Arbitrary Custom Shapes. polygon() takes a list of x/y coordinate pairs (as percentages or lengths) defining the vertices of an arbitrary shape ā a triangle, a hexagon, an arrow, a diagonal-cut banner ā clipping the element to exactly that custom-defined region, the most flexible clip-path tool for shapes basic functions can't express.
Understanding polygon(). What do the coordinate pairs inside polygon() represent?
- āColor gradient stop positions
- āThe vertices (corner points) of the custom polygon shape the element will be clipped to
- āAnimation keyframe timing values
Animating clip-path For Reveal Effects. Because clip-path resolves to a single, interpolatable shape value, transitioning between two polygon() definitions with the same number of points produces a smooth morphing/revealing animation ā a common pattern for image reveal effects, expanding shape transitions, or a menu that unfolds from a corner.
Animating clip-path. What's required for a clip-path transition between two polygon() values to animate smoothly, rather than jumping abruptly?
- āBoth polygons must use the same fill color
- āBoth polygon() definitions generally need the same number of points for the browser to interpolate between them smoothly
- āThere's no requirement ā any two polygons will always animate smoothly
clip-path Mastered. You can now clip elements into circles and insets with concise basic shape functions, build entirely custom polygon shapes vertex by vertex, and animate between clip-path shapes for smooth, GPU-friendly reveal and morphing effects.
Clip An Element Into A Circle. clip-path: circle() crops an element to a circular shape.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Clipped Content Must Never Remove Meaningful Information A User Actually Needs To Perceive
clip-path visually hides everything outside its shape, but that content may still be technically present in the DOM ā verify clipped-away content isn't accidentally still announced to screen readers if it shouldn't be, or conversely, isn't hiding genuinely necessary information from sighted users.
2Custom Shapes Should Preserve Sufficient Interactive Target Area For Any Clickable Elements They're Applied To
A heavily-clipped interactive element (like a hexagonal button) can reduce its effective clickable area below accessible touch-target size minimums ā verify the clipped shape still provides adequate interactive area.
SEO Implications
- 1
CSS-Based Custom Shapes Replace Image-Based Shape Assets, Reducing Page Weight
A diagonal-cut banner or hexagonal card achieved via clip-path avoids needing a separate PNG mask or SVG asset, directly reducing image payload and associated HTTP requests.
- 2
clip-path Animations Are Generally GPU-Friendly Compared To Alternative JavaScript-Based Shape Morphing
Native CSS shape interpolation avoids the JavaScript computation and potential layout thrashing that a hand-rolled shape-morphing animation might otherwise introduce.
Best Practices
Use Basic Shape Functions (circle, ellipse, inset) Instead Of polygon() Whenever The Shape Is Regular
They're more concise, more readable, and communicate intent more directly than an equivalent polygon() definition for shapes that don't need arbitrary vertex control.
Keep Matching Point Counts Between Two Animated polygon() States For Smooth, Predictable Interpolation
This avoids jarring or unexpected morphing behavior during the transition, ensuring each vertex animates predictably to its corresponding target position.
Frequent Bugs
An animated clip-path transition between two different polygon shapes jumps abruptly instead of morphing smoothly.
Check that both polygon() definitions have the same number of points; add matching 'redundant' points to the simpler shape if needed for smooth interpolation.
A clip-path shape looks correct but the clickable area of a button styled with it feels smaller than expected.
clip-path removes the interactive hit area outside the clipped shape too; verify the shape still provides an adequately-sized clickable region, or adjust the underlying element's size.
Real-World Examples
A CSS-Only Diagonal Section Divider
A landing page section with a diagonal-cut bottom edge transitioning into the next section, achieved entirely with clip-path and no image assets.
.hero-section {
clip-path: polygon(0 0, 100% 0, 100% 85%, 0 100%);
}