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:

  1. Start at the top-center point.
  2. Draw a straight line to the bottom-right point.
  3. Draw a straight line to the bottom-left point.
  4. 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()
SyntaxComma-separated coordinate pairsSVG path commands in a quoted string
LinesStraight segmentsStraight and curved segments
PercentagesSupportedNot supported inside path data
CSS calculationsSupportedNot supported inside path data
Responsive sizingConvenient with percentagesFixed numeric coordinates
Typical useGeometric shapesComplex 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%);
}
Browser Result

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;
  }
}
Browser Result

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 shapesCreate triangles, diamonds, arrows, stars, and other polygons.
Image clippingDisplay images inside custom geometric boundaries.
Decorative sectionsCreate angled edges and nonrectangular backgrounds.
Text wrappingDefine polygon-shaped boundaries around floated elements.
Responsive designsUse percentage coordinates that scale with the reference box.
Hover effectsAnimate between compatible polygon shapes.
Interface graphicsCreate 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() or shape().
  • 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-outside requires 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().