Difficulty: Advanced
CSS clip-path allows you to create complex shapes by clipping (masking) elements to a defined region. Only the portion of the element inside the clipping region is visible; everything outside is hidden. Unlike border-radius which only creates rounded rectangles, clip-path can create any shape imaginable - triangles, hexagons, stars, custom polygons, and smooth curves. The clipped content is still in the document flow, occupying its original rectangular space.
The polygon() function is the most versatile clip-path shape. It defines a shape using a series of x,y coordinate pairs that form the vertices of a polygon. Coordinates can be percentages (relative to the element's dimensions) or absolute lengths. For example, polygon(50% 0%, 100% 100%, 0% 100%) creates a triangle with the top point centered and the base at the bottom. Points are connected in order, and the path is automatically closed. You can create any polygon - triangles, pentagons, hexagons, arrows, chevrons, and completely custom shapes.
The circle() function creates a circular clip at a given radius and position. The syntax is circle(radius at centerX centerY). If omitted, the circle is centered in the element. The ellipse() function works similarly but accepts two radii for horizontal and vertical axes: ellipse(radiusX radiusY at centerX centerY). The inset() function creates a rectangle inset from the edges, with optional rounded corners: inset(top right bottom left round borderRadius). This is useful for animated reveals where you expand from a small rectangle to the full element.
Clip-path is animatable, making it a powerful tool for creative transitions. You can transition between shapes with the same number of vertices (e.g., one polygon to another polygon with the same number of points), circles with different radii, or insets with different dimensions. The browser smoothly interpolates between the coordinate values. This enables dramatic reveal effects, morphing shapes, and creative hover transitions that go far beyond standard CSS capabilities.
The shape-outside property is related but serves a different purpose: it defines a shape that inline content (text) wraps around when used with floated elements. While clip-path clips the visual rendering of an element, shape-outside affects the flow of surrounding content. Combining both on the same element - clip-path for the visual shape and shape-outside for text wrapping - creates magazine-style layouts where text flows around non-rectangular images.
/* Triangle */
.triangle {
clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
}
/* Pentagon */
.pentagon {
clip-path: polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%);
}
/* Hexagon */
.hexagon {
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
}
/* Arrow pointing right */
.arrow {
clip-path: polygon(0% 20%, 60% 20%, 60% 0%, 100% 50%, 60% 100%, 60% 80%, 0% 80%);
}
/* Chevron */
.chevron {
clip-path: polygon(0% 0%, 75% 0%, 100% 50%, 75% 100%, 0% 100%, 25% 50%);
}
/* Star */
.star {
clip-path: polygon(
50% 0%, 61% 35%, 98% 35%, 68% 57%,
79% 91%, 50% 70%, 21% 91%, 32% 57%,
2% 35%, 39% 35%
);
}
/* Diamond */
.diamond {
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}
polygon() defines shapes with x,y vertex coordinates as percentages of the element's width and height. 0% 0% is top-left, 100% 100% is bottom-right. The browser connects vertices in order and closes the path automatically. More vertices create more complex shapes.
/* Circle: radius at position */
.circle-clip {
clip-path: circle(50% at 50% 50%); /* Full circle centered */
}
.circle-small {
clip-path: circle(30% at 50% 50%); /* Smaller circle */
}
.circle-offset {
clip-path: circle(40% at 30% 40%); /* Off-center circle */
}
/* Ellipse: radiusX radiusY at position */
.ellipse-clip {
clip-path: ellipse(50% 35% at 50% 50%);
}
/* Inset: top right bottom left with optional rounding */
.inset-clip {
clip-path: inset(10% 10% 10% 10%);
}
.inset-rounded {
clip-path: inset(5% round 20px);
}
/* Animated circle reveal */
.reveal {
clip-path: circle(0% at 50% 50%);
transition: clip-path 0.6s ease-out;
}
.reveal.active {
clip-path: circle(75% at 50% 50%);
}
/* Animated inset reveal (curtain effect) */
.curtain {
clip-path: inset(0 50% 0 50%);
transition: clip-path 0.5s ease;
}
.curtain.open {
clip-path: inset(0 0 0 0);
}
circle() and ellipse() create curved clipping regions. inset() creates rectangular clips with optional rounding - useful for reveal animations. All these shapes are smoothly animatable via CSS transitions.
/* Hover morph: rectangle to circle */
.morph {
clip-path: inset(0 round 8px);
transition: clip-path 0.4s ease;
}
.morph:hover {
clip-path: circle(50% at 50% 50%);
}
/* Polygon morphing (same number of points required) */
.shape-morph {
clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
transition: clip-path 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.shape-morph:hover {
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}
/* Diagonal reveal on scroll */
.diagonal-reveal {
clip-path: polygon(0 0, 0 0, 0 100%, 0 100%);
transition: clip-path 0.8s ease;
}
.diagonal-reveal.visible {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
/* Creative page transition */
@keyframes wipeIn {
from {
clip-path: circle(0% at 50% 50%);
}
to {
clip-path: circle(100% at 50% 50%);
}
}
.page-enter {
animation: wipeIn 0.8s ease-out forwards;
}
Clip-path transitions work when the shapes have the same type and number of points. Polygons must have equal vertex counts to morph smoothly. Circle and inset animations are smooth by default. These create dramatic reveal and morphing effects.
/* Float an image with circular text wrapping */
.circular-image {
float: left;
width: 200px;
height: 200px;
border-radius: 50%;
clip-path: circle(50%);
shape-outside: circle(50%);
margin-right: 20px;
}
/* Text wraps around the actual circle, not the bounding box */
/* Custom polygon text wrap */
.diamond-float {
float: left;
width: 200px;
height: 200px;
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
shape-outside: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
shape-margin: 16px; /* Adds space between shape and text */
}
/* Elliptical text wrap */
.ellipse-float {
float: right;
width: 250px;
height: 300px;
clip-path: ellipse(50% 50%);
shape-outside: ellipse(50% 50%);
shape-margin: 12px;
}
/* Using an image's alpha channel for text wrapping */
.alpha-shape {
float: left;
width: 200px;
shape-outside: url('shape.png');
shape-image-threshold: 0.5;
shape-margin: 10px;
}
shape-outside defines the area around which inline content wraps when used with float. Combining clip-path (visual) with shape-outside (flow) creates magazine-style layouts. shape-margin adds breathing room between the shape edge and wrapping text.
clip-path, polygon(), circle(), ellipse(), shape-outside