CSS polygon() Function
The CSS polygon() function defines a custom geometric shape by connecting a series of coordinate points with straight lines.
It is commonly used with clip-path to create triangles, diamonds, arrows, and other custom shapes. It can also be used with shape-outside to control text wrapping around floated elements. Coordinates can use percentages, lengths, and CSS calculations.
Syntax
polygon(x1 y1, x2 y2, x3 y3, ...)
polygon(fill-rule, x1 y1, x2 y2, x3 y3, ...)
Each coordinate pair defines one point in the polygon. A comma separates each point.
For example:
clip-path: polygon(50% 0, 100% 100%, 0 100%);
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
clip-path: polygon(evenodd, 0 0, 100% 0, 100% 100%, 0 100%);
The first example defines a triangle, while the second defines a rectangle.
The optional fill-rule parameter controls how overlapping areas are filled.
The function produces a CSS <basic-shape> value and is used within properties that accept basic shapes.
Parameters
The polygon() function accepts coordinate pairs and an optional fill rule.
| Parameter | Description |
|---|---|
x y |
A pair of length or percentage values defining the horizontal and vertical position of a point. |
fill-rule |
An optional nonzero or evenodd keyword controlling how the polygon's interior is determined. |
For example:
polygon(50% 0, 100% 100%, 0 100%)
This polygon contains three points:
50% 0- top center.100% 100%- bottom right.0 100%- bottom left.
At least three points are generally needed to create a filled area with a visible shape.
Although the syntax permits fewer points, they do not define an ordinary filled polygon.
How It Works
The polygon() function creates a shape by connecting coordinate points in the order they are listed.
For example:
clip-path: polygon(50% 0, 100% 100%, 0 100%);
The browser constructs the shape as follows:
- Start at the top-center point.
- Draw a straight line to the bottom-right point.
- Draw a straight line to the bottom-left point.
- Close the shape by connecting the final point to the first point.
The result is a triangle.
When used with clip-path, only the area inside the polygon remains visible.
When used with shape-outside, the polygon defines a boundary that inline content wraps around.
The polygon does not alter the element's original layout dimensions.
Coordinate Points
Each point contains two values representing its horizontal and vertical position.
The first value controls the x-coordinate, while the second controls the y-coordinate.
For example:
polygon(0 0, 100% 0, 100% 100%, 0 100%)
This defines four corners of a rectangle.
The coordinate system begins at the top-left corner of the reference box:
0 0- top left.100% 0- top right.100% 100%- bottom right.0 100%- bottom left.
Points are connected in the order they appear, so changing their order can change the resulting shape.
For example:
polygon(0 0, 100% 100%, 100% 0, 0 100%)
This connects the corners in a different order and creates a self-intersecting polygon.
For ordinary shapes, list points around the perimeter in clockwise or counterclockwise order.
Percentage Values
Percentages are commonly used because they allow polygon coordinates to adjust to the size of the reference box.
For example:
.triangle {
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
The triangle scales with the element's dimensions.
Another example creates a diamond:
.diamond {
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
The percentages describe positions relative to the reference box's width and height.
For example, 50% 0 is halfway across the width and at the top edge.
Percentage-based polygons are useful for responsive layouts because they do not depend on fixed pixel coordinates.
Length Values
The polygon() function also accepts CSS length values.
For example:
.triangle {
clip-path: polygon(100px 0, 200px 200px, 0 200px);
}
This defines a triangle using fixed pixel coordinates.
Lengths and percentages can be combined:
.banner {
clip-path: polygon(
0 0,
100% 0,
100% calc(100% - 30px),
50% 100%,
0 calc(100% - 30px)
);
}
The calc() function allows coordinates to combine different units.
This example creates a banner with a pointed bottom edge that remains 30 pixels deep.
Use percentages for scalable shapes and lengths when specific dimensions or offsets are needed.
Fill Rules
The optional fill rule determines which areas of a polygon are considered inside the shape, particularly when its edges overlap.
Two fill rules are supported:
| Value | Description |
|---|---|
nonzero |
Uses the nonzero winding rule to determine filled areas. This is the default. |
evenodd |
Uses the even-odd rule, alternating filled and unfilled regions based on boundary crossings. |
For example:
clip-path: polygon(nonzero, 0 0, 100% 0, 100% 100%, 0 100%);
clip-path: polygon(evenodd, 0 0, 100% 0, 100% 100%, 0 100%);
Both produce the same result for this simple rectangle.
The difference becomes visible with self-intersecting polygons.
For ordinary triangles, diamonds, and other simple shapes, the default nonzero rule is usually sufficient.
Common Polygon Shapes
The polygon() function can create many familiar shapes using coordinate points.
Triangle
clip-path: polygon(50% 0, 100% 100%, 0 100%);
Diamond
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
Pentagon
clip-path: polygon(50% 0, 100% 38%, 82% 100%, 18% 100%, 0 38%);
Hexagon
clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
Arrow
clip-path: polygon(0 25%, 65% 25%, 65% 0, 100% 50%, 65% 100%, 65% 75%, 0 75%);
Star
clip-path: polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
These shapes use percentage coordinates, allowing them to adjust to different element sizes.
For complex polygons, visual shape generators can make it easier to position points accurately.
Using polygon() with clip-path
The clip-path property is the most common use of polygon().
It defines the visible region of an element without changing its layout box.
For example:
.shape {
width: 200px;
height: 200px;
background-color: #0066cc;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
The rectangular element is clipped into a triangle.
The same technique can be applied to images:
.image {
width: 250px;
height: 250px;
object-fit: cover;
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
The image is displayed inside a diamond-shaped clipping region.
Clipped content outside the polygon is hidden, so important text and interactive controls should remain inside the visible area.
Using polygon() with shape-outside
The shape-outside property can use polygon() to control how text wraps around a floated element.
For example:
.float-shape {
float: left;
width: 180px;
height: 180px;
margin-right: 15px;
background-color: #0066cc;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
shape-outside: polygon(50% 0, 100% 100%, 0 100%);
}
The clip-path property controls the visible shape, while shape-outside controls the wrapping boundary.
The element must be floated for shape-outside to affect surrounding inline content.
The shape-margin property can add spacing between the shape and the wrapped text.
For example:
.float-shape {
shape-margin: 15px;
}
Using matching polygon values for clipping and text wrapping helps the visible shape align with the text boundary.
Responsive Shapes
Percentage-based polygon coordinates automatically adjust to the reference box's dimensions.
For example:
.responsive-shape {
width: 100%;
aspect-ratio: 2 / 1;
background-color: #0066cc;
clip-path: polygon(0 0, 100% 0, 90% 100%, 10% 100%);
}
The trapezoid scales as the element becomes wider or narrower.
The aspect-ratio property helps maintain consistent proportions.
Mixed percentage and length values can preserve fixed details:
.responsive-banner {
clip-path: polygon(
0 0,
100% 0,
100% calc(100% - 25px),
50% 100%,
0 calc(100% - 25px)
);
}
This keeps the pointed bottom section 25 pixels deep while the width adjusts.
For responsive designs, percentage coordinates are generally easier to maintain than fixed pixel coordinates.
Animating Polygon Shapes
Polygon coordinates can be animated using CSS transitions and keyframe animations.
For reliable interpolation, the starting and ending polygons should use the same number of points and compatible coordinate values.
For example:
.animated-shape {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
transition: clip-path 0.5s ease;
}
.animated-shape:hover {
clip-path: polygon(50% 0, 100% 100%, 50% 100%, 0 100%);
}
Both shapes contain four coordinate points.
The browser can interpolate corresponding points to produce a smooth transition.
If the polygons contain different numbers of points, the browser may not be able to interpolate between them smoothly.
For accessibility, avoid unnecessary motion and respect the user's reduced-motion preference.
polygon() vs. path()
The polygon() and path() functions both define custom shapes, but they use different coordinate systems and syntax.
| Feature | polygon() | path() |
|---|---|---|
| Syntax | Comma-separated coordinate pairs | SVG path commands in a quoted string |
| Lines | Straight segments | Straight and curved segments |
| Percentages | Supported | Not supported inside path data |
| CSS calculations | Supported | Not supported inside path data |
| Responsive sizing | Convenient with percentages | Fixed numeric coordinates |
| Typical use | Geometric shapes | Complex SVG-based shapes and motion paths |
For example, a triangle using polygon():
clip-path: polygon(50% 0, 100% 100%, 0 100%);
A triangle using path():
clip-path: path("M 100 0 L 200 200 L 0 200 Z");
The polygon() version scales with the reference box.
The path() version uses fixed SVG coordinates.
Use polygon() for responsive shapes made from straight lines, and path() when curves or existing SVG path data are required.
Example
This example demonstrates four shapes created using polygon().
HTML:
<div class="polygon-demo">
<div class="polygon-demo-item">
<div class="polygon-demo-shape polygon-triangle"></div>
<p>Triangle</p>
</div>
<div class="polygon-demo-item">
<div class="polygon-demo-shape polygon-diamond"></div>
<p>Diamond</p>
</div>
<div class="polygon-demo-item">
<div class="polygon-demo-shape polygon-hexagon"></div>
<p>Hexagon</p>
</div>
<div class="polygon-demo-item">
<div class="polygon-demo-shape polygon-star"></div>
<p>Star</p>
</div>
</div>
CSS:
.polygon-demo {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.polygon-demo-item {
text-align: center;
}
.polygon-demo-shape {
width: 140px;
height: 140px;
}
.polygon-demo-item p {
margin: 10px 0 0;
}
.polygon-triangle {
background-color: #0066cc;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.polygon-diamond {
background-color: #00a896;
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
.polygon-hexagon {
background-color: #cc6600;
clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}
.polygon-star {
background-color: #8844aa;
clip-path: polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}
Triangle
Diamond
Hexagon
Star
Each shape uses the same width and height, but different polygon coordinates create different outlines.
Because the coordinates use percentages, the shapes can scale with their elements.
Hover Example
This example animates a square into a diamond when the pointer moves over it.
HTML:
<div class="polygon-hover-demo">
<div class="polygon-hover-shape"></div>
<p>Hover over the shape.</p>
</div>
CSS:
.polygon-hover-demo {
padding: 25px;
background-color: #f1f3f5;
text-align: center;
}
.polygon-hover-shape {
width: 160px;
height: 160px;
margin: 0 auto;
background-color: #0066cc;
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
transition: clip-path 0.5s ease;
}
.polygon-hover-shape:hover {
clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
.polygon-hover-demo p {
margin: 15px 0 0;
}
@media (prefers-reduced-motion: reduce) {
.polygon-hover-shape {
transition: none;
}
}
Hover over the shape.
The starting and ending polygons each contain four points, allowing the browser to interpolate between corresponding coordinates.
The transition creates a smooth change from a square to a diamond.
When reduced motion is requested, the transition is disabled.
Common Uses
The polygon() function is useful for creating custom geometric shapes and layout effects.
| Use | Description |
|---|---|
| Custom shapes | Create triangles, diamonds, arrows, stars, and other polygons. |
| Image clipping | Display images inside custom geometric boundaries. |
| Decorative sections | Create angled edges and nonrectangular backgrounds. |
| Text wrapping | Define polygon-shaped boundaries around floated elements. |
| Responsive designs | Use percentage coordinates that scale with the reference box. |
| Hover effects | Animate between compatible polygon shapes. |
| Interface graphics | Create decorative badges, arrows, and geometric accents. |
For example:
.arrow {
clip-path: polygon(0 25%, 65% 25%, 65% 0, 100% 50%, 65% 100%, 65% 75%, 0 75%);
}
.angled-section {
clip-path: polygon(0 0, 100% 0, 100% 90%, 0 100%);
}
.badge {
clip-path: polygon(50% 0, 100% 38%, 82% 100%, 18% 100%, 0 38%);
}
These examples create decorative shapes without requiring separate image files.
Limitations
The polygon() function has several important rules and limitations.
- Each point requires two coordinate values.
- Points must be separated by commas.
- The function connects points using straight lines only.
- Curved edges require another shape function, such as
path()orshape(). - The polygon closes automatically by connecting the final point to the first point.
- Self-intersecting polygons can produce different filled regions depending on the fill rule.
- Clipping does not change the element's layout dimensions.
- Content outside the clipping region is hidden.
- Text wrapping with
shape-outsiderequires a floated element. - Smooth animation generally requires matching point counts and compatible coordinate values.
For example, this is valid:
clip-path: polygon(50% 0, 100% 100%, 0 100%);
The following is invalid because the coordinate pairs are not separated by commas:
clip-path: polygon(50% 0 100% 100% 0 100%);
The following is also invalid because one point contains only a single coordinate:
clip-path: polygon(50% 0, 100%, 0 100%);
For predictable results, define points in a consistent order and test the shape at different element sizes.
Browser Support
The CSS polygon() function is Baseline Widely available and is supported by modern versions of Chrome, Edge, Firefox, Safari, and other major browsers.
It is commonly supported with the clip-path and shape-outside properties.
For example:
.shape {
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
Modern browsers support this declaration without vendor prefixes.
For current compatibility information, visit Can I Use? and search for CSS clip-path or CSS Shapes.
Specifications
The polygon() function is defined in the CSS Shapes Module Level 1 .
The specification defines polygon coordinate syntax, fill rules, and how basic shapes are interpreted by compatible CSS properties.
Related CSS functions include circle(), ellipse(), inset(), path(), and shape().
