CSS path() Function
The CSS path() function defines a custom shape or motion path using SVG path commands.
It allows developers to create complex clipping shapes, control text wrapping, and move elements along custom paths. The function uses SVG path data inside a quoted string and can be used with properties such as clip-path, offset-path, and shape-outside.
Syntax
path("SVG path data")
path(fill-rule, "SVG path data")
The function accepts a quoted string containing SVG path commands. An optional fill rule can be included where the property supports it.
For example:
clip-path: path("M 0 0 L 200 0 L 100 150 Z");
offset-path: path("M 0 100 Q 150 0 300 100");
shape-outside: path("M 0 0 L 150 0 L 75 150 Z");
The commands define coordinates, straight lines, curves, and other parts of the path.
For clipping shapes, a fill rule can be specified:
clip-path: path(evenodd, "M 0 0 H 200 V 200 H 0 Z");
The path() function is a CSS basic shape function. It does not load an external SVG file.
Unlike ordinary CSS length values, coordinates inside the quoted path data are SVG path numbers and cannot contain units such as px or %.
Parameters
The path() function accepts SVG path data and an optional fill rule.
| Parameter | Description |
|---|---|
SVG path data |
A quoted string containing SVG path commands and numeric coordinates. |
fill-rule |
An optional nonzero or evenodd keyword controlling how overlapping areas are filled in applicable shape contexts. |
For example:
path("M 0 0 L 200 0 L 100 150 Z")
This defines a triangular path using four commands.
The first command moves to the starting position, the next two draw lines, and the final command closes the path.
SVG path commands are case-sensitive. Uppercase and lowercase letters can produce different coordinate behavior.
How It Works
The path() function converts SVG path instructions into a geometric path that CSS can use for clipping, motion, or text wrapping.
For example:
clip-path: path("M 0 0 L 200 0 L 100 150 Z");
The path is constructed as follows:
M 0 0moves the starting point to coordinates 0, 0.L 200 0draws a line to coordinates 200, 0.L 100 150draws a line to coordinates 100, 150.Zcloses the path by connecting the final point to the starting point.
When applied to clip-path, the path defines the visible portion of an element.
When applied to offset-path, the path provides a route along which an element can move.
The same path data can therefore serve different purposes depending on the CSS property.
SVG Path Commands
The path() function uses the path commands defined by SVG.
| Command | Name | Description |
|---|---|---|
M, m | Move To | Moves the current point without drawing a line. |
L, l | Line To | Draws a straight line to another point. |
H, h | Horizontal Line | Draws a horizontal line. |
V, v | Vertical Line | Draws a vertical line. |
C, c | Cubic Curve | Draws a cubic Bézier curve using two control points. |
S, s | Smooth Cubic Curve | Continues a cubic curve using a reflected control point when applicable. |
Q, q | Quadratic Curve | Draws a quadratic Bézier curve using one control point. |
T, t | Smooth Quadratic Curve | Continues a quadratic curve using a reflected control point when applicable. |
A, a | Elliptical Arc | Draws an elliptical arc. |
Z, z | Close Path | Closes the current subpath. |
For example:
path("M 10 10 H 190 V 140 H 10 Z")
This defines a rectangular shape using move, horizontal, vertical, and close commands.
Commands can be separated by spaces, and SVG path syntax also permits compact coordinate notation.
For beginner-friendly examples, spaces between commands and values make paths easier to read.
Absolute and Relative Commands
SVG path commands use uppercase letters for absolute coordinates and lowercase letters for relative coordinates.
Absolute coordinates refer to positions in the path's coordinate system.
For example:
path("M 20 20 L 120 20 L 120 120 Z")
Each L command specifies the destination coordinates directly.
Relative commands use offsets from the current point:
path("M 20 20 l 100 0 l 0 100 Z")
Both examples define the same triangular path.
In the second example, l 100 0 moves 100 units to the right, while l 0 100 moves 100 units downward.
Relative commands can make paths easier to modify when several segments are based on the previous position.
Creating Straight Lines
Straight-line paths are created using the L, H, and V commands.
For example, a triangle:
clip-path: path("M 100 0 L 200 200 L 0 200 Z");
A rectangle:
clip-path: path("M 0 0 H 200 V 150 H 0 Z");
A diamond:
clip-path: path("M 100 0 L 200 100 L 100 200 L 0 100 Z");
These examples use fixed numeric coordinates.
For simple geometric shapes that should scale with their element, CSS functions such as polygon() may be easier to maintain.
Creating Curved Paths
Curved paths can be created using cubic or quadratic Bézier commands.
The Q command uses one control point:
offset-path: path("M 0 100 Q 150 0 300 100");
The path begins at 0, 100, curves toward the control point at 150, 0, and ends at 300, 100.
The C command uses two control points:
offset-path: path("M 0 100 C 100 0 200 200 300 100");
This creates a more flexible curve that can change direction along its route.
Curves can also form closed clipping shapes:
clip-path: path("M 0 50 Q 100 0 200 50 L 200 150 L 0 150 Z");
This creates a shape with a curved upper edge and straight sides.
For more complex curves, SVG editing software can help generate the required path data.
Closing Paths
The Z or z command closes the current subpath by connecting its final point to its starting point.
For example:
path("M 0 0 L 200 0 L 100 150 Z")
The final command completes the triangle.
Without Z, the path remains open:
path("M 0 0 L 200 0 L 100 150")
Open paths are useful for motion paths because an element can follow the route without returning to its starting position.
For filled shapes, the fill operation treats open subpaths as closed, but explicitly using Z makes the intended boundary clearer.
Use closed paths for complete geometric outlines and open paths when defining routes that should have distinct starting and ending points.
Fill Rules
The optional fill rule determines which areas of a path are considered inside the shape when subpaths overlap.
Two fill rules are available:
| Value | Description |
|---|---|
nonzero | Uses the nonzero winding rule to determine filled regions. This is the default. |
evenodd | Determines filled regions by counting boundary crossings, alternating between filled and unfilled areas. |
For example:
clip-path: path(nonzero, "M 0 0 H 200 V 200 H 0 Z");
clip-path: path(evenodd, "M 0 0 H 200 V 200 H 0 Z");
Both produce the same result for this simple rectangle.
The difference becomes visible when a path contains overlapping or nested subpaths.
For example, this path defines an outer rectangle and an inner rectangle:
clip-path: path(evenodd, "M 0 0 H 200 V 200 H 0 Z M 50 50 H 150 V 150 H 50 Z");
With evenodd, the inner rectangle becomes a hole in the clipping region.
Fill rules apply to filled shape calculations. They do not control the direction an element travels along a motion path.
Using path() with clip-path
The clip-path property can use path() to define the visible region of an element.
For example:
.triangle {
width: 200px;
height: 200px;
background-color: #0066cc;
clip-path: path("M 100 0 L 200 200 L 0 200 Z");
}
The element retains its rectangular layout box, but only the triangular region is painted.
Another example creates a custom banner shape:
.banner {
width: 300px;
height: 150px;
background-color: #00a896;
clip-path: path("M 0 0 H 300 V 100 L 150 150 L 0 100 Z");
}
The shape has a rectangular upper section and a pointed lower edge.
Clipping does not change the element's layout dimensions.
Content outside the clipping region is hidden, so important text and controls should remain within the visible area.
Using path() with offset-path
The offset-path property uses path() to define a route for CSS motion path positioning.
For example:
.moving-box {
offset-path: path("M 0 100 Q 150 0 300 100");
offset-distance: 50%;
}
The offset-path property defines the route, while offset-distance controls the element's position along it.
For example:
.start {
offset-distance: 0%;
}
.middle {
offset-distance: 50%;
}
.end {
offset-distance: 100%;
}
The percentages represent positions along the total path length, not percentages of the element's width.
The path can also be animated:
.moving-box {
offset-path: path("M 0 100 Q 150 0 300 100");
animation: follow-path 4s linear infinite alternate;
}
@keyframes follow-path {
from {
offset-distance: 0%;
}
to {
offset-distance: 100%;
}
}
The element moves from the beginning to the end of the curved path and then reverses direction.
The offset-rotate property can control whether the element rotates to follow the path's direction.
Using path() with shape-outside
The shape-outside property can use path() to define how inline content wraps around a floated element.
For example:
.float-shape {
float: left;
width: 200px;
height: 200px;
shape-outside: path("M 100 0 L 200 200 L 0 200 Z");
clip-path: path("M 100 0 L 200 200 L 0 200 Z");
background-color: #0066cc;
margin-right: 15px;
}
The shape-outside declaration defines the wrapping boundary.
The clip-path declaration gives the floated element a matching visible shape.
The element must be floated for shape-outside to affect text wrapping.
The shape-outside property does not clip the element by itself.
For simple responsive wrapping shapes, circle(), ellipse(), or polygon() may be more convenient.
Responsive Paths
One important limitation of path() is that its SVG path coordinates use fixed numeric values.
For example:
.shape {
clip-path: path("M 0 0 L 200 0 L 100 150 Z");
}
The path coordinates do not automatically scale when the element's width or height changes.
Changing the element to width: 100% does not convert the path coordinates into percentages.
For a responsive triangle, polygon() is often simpler:
.shape {
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
The percentage coordinates adjust with the element's dimensions.
The newer shape() function also supports CSS lengths and percentages, allowing more flexible custom paths where supported.
Use path() when fixed SVG path coordinates are suitable or when working with path data generated by SVG tools.
path() vs. shape()
The path() and shape() functions both define custom geometric shapes, but their syntax and coordinate handling differ.
| Feature | path() | shape() |
|---|---|---|
| Syntax | SVG path commands in a quoted string | CSS shape commands |
| Coordinates | Fixed SVG numeric coordinates | CSS lengths, percentages, and calculations |
| Responsive sizing | Limited | Supports relative coordinates |
| Custom properties | Cannot substitute values inside the path string | Can use CSS values and custom properties in commands |
| Typical use | Existing SVG path data and fixed shapes | Flexible CSS-defined shapes |
For example, a triangle using path():
clip-path: path("M 100 0 L 200 200 L 0 200 Z");
A similar triangle using shape():
clip-path: shape(
from 50% 0,
line to 100% 100%,
line to 0 100%,
close
);
The shape() version uses percentages that can adjust with the element's size.
Browser support for shape() is newer and should be checked separately.
Example
This example uses path() to clip three colored boxes into different geometric shapes.
HTML:
<div class="path-demo">
<div class="path-demo-item">
<div class="path-demo-shape path-demo-triangle"></div>
<p>Triangle</p>
</div>
<div class="path-demo-item">
<div class="path-demo-shape path-demo-diamond"></div>
<p>Diamond</p>
</div>
<div class="path-demo-item">
<div class="path-demo-shape path-demo-pentagon"></div>
<p>Pentagon</p>
</div>
</div>
CSS:
.path-demo {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 20px;
}
.path-demo-item {
text-align: center;
}
.path-demo-item p {
margin: 10px 0 0;
}
.path-demo-shape {
width: 160px;
height: 160px;
}
.path-demo-triangle {
background-color: #0066cc;
clip-path: path("M 80 0 L 160 160 L 0 160 Z");
}
.path-demo-diamond {
background-color: #00a896;
clip-path: path("M 80 0 L 160 80 L 80 160 L 0 80 Z");
}
.path-demo-pentagon {
background-color: #cc6600;
clip-path: path("M 80 0 L 160 60 L 130 160 L 30 160 L 0 60 Z");
}
Triangle
Diamond
Pentagon
Each box has the same dimensions, but its clip-path declaration defines a different visible outline.
The SVG path coordinates match the fixed 160-pixel dimensions used in this demonstration.
Motion Path Example
This example animates a circular element along a curved path using offset-path and offset-distance.
HTML:
<div class="path-motion-demo">
<div class="path-motion-object"></div>
</div>
CSS:
.path-motion-demo {
position: relative;
width: 100%;
max-width: 360px;
height: 180px;
margin: 0 auto;
overflow: hidden;
background-color: #f1f3f5;
border: 1px solid #dddddd;
}
.path-motion-object {
position: absolute;
top: 0;
left: 0;
width: 24px;
height: 24px;
border-radius: 50%;
background-color: #0066cc;
offset-path: path("M 30 130 Q 180 10 330 130");
offset-rotate: 0deg;
animation: path-motion 4s linear infinite alternate;
}
@keyframes path-motion {
from {
offset-distance: 0%;
}
to {
offset-distance: 100%;
}
}
@media (prefers-reduced-motion: reduce) {
.path-motion-object {
animation: none;
offset-distance: 50%;
}
}
The blue circle follows the quadratic curve from left to right and then reverses direction.
The offset-distance property changes from 0% to 100% during the animation.
The offset-rotate: 0deg declaration keeps the circle's orientation fixed.
When reduced motion is requested, the animation stops and the circle remains at the midpoint of the path.
The path uses fixed coordinates, so the complete route requires sufficient horizontal space. For smaller layouts, adjust the coordinates or use a responsive alternative.
Common Uses
The path() function is useful when CSS needs a custom geometric shape or movement route.
| Use | Description |
|---|---|
| Custom clipping | Clip elements into irregular or curved shapes. |
| Motion paths | Move elements along straight or curved routes. |
| Text wrapping | Define custom boundaries for text around floated elements. |
| Decorative graphics | Create nonrectangular visual effects. |
| SVG integration | Reuse SVG path data in CSS declarations. |
| Complex outlines | Combine multiple lines, curves, and subpaths. |
For example:
.custom-shape {
clip-path: path("M 0 0 H 200 L 150 150 H 0 Z");
}
.moving-icon {
offset-path: path("M 0 50 C 100 0 200 100 300 50");
}
.floated-shape {
float: left;
shape-outside: path("M 0 0 L 150 0 L 75 150 Z");
}
These declarations demonstrate how one function can be used for different geometric purposes.
Limitations
The path() function has several important rules and limitations.
- SVG path data must be enclosed in quotation marks.
- Path commands are case-sensitive.
- Coordinates inside the string use SVG numeric values, not CSS lengths or percentages.
- Path coordinates do not automatically scale with the element's dimensions.
- CSS custom properties cannot be substituted into individual coordinates inside the quoted string.
- Invalid SVG path data can cause the CSS shape value to be invalid.
- Clipping affects the visible region but does not change the element's layout box.
- Motion paths require additional properties, such as
offset-distance, to control position. - Text wrapping with
shape-outsiderequires a floated element. - Complex paths can be difficult to edit manually.
- Browser compatibility depends on the CSS property using the function.
For example, this is valid:
clip-path: path("M 0 0 L 200 0 L 100 150 Z");
The following is invalid because the path data is not quoted:
clip-path: path(M 0 0 L 200 0 L 100 150 Z);
The following is also invalid because CSS percentage units cannot be used inside the SVG path string:
clip-path: path("M 50% 0 L 100% 100% L 0 100% Z");
For percentage-based shapes, use polygon() or a supported shape() declaration instead.
Browser Support
The CSS path() function is Baseline Widely available for established uses such as clip-path and offset-path in modern browsers.
Modern versions of Chrome, Edge, Firefox, Safari, and other major browsers support SVG path data in CSS for these uses.
Support can differ depending on the property, optional syntax, and browser version.
For example:
.shape {
clip-path: polygon(50% 0, 100% 100%, 0 100%);
clip-path: path("M 100 0 L 200 200 L 0 200 Z");
}
The polygon() declaration provides a fallback shape, while supporting browsers use the later path() declaration.
The two shapes assume a 200-by-200-pixel element for an equivalent result.
For current compatibility information, visit Can I Use? and search for CSS path() function, CSS clip-path, or CSS Motion Path.
Specifications
The path() function is defined in the CSS Shapes Module Level 1 .
The path command syntax is defined by the SVG 2 specification .
Motion path behavior is covered by the Motion Path Module Level 1 .
Related CSS functions include polygon(), circle(), ellipse(), inset(), and shape().
