The CSS Shapes specification has moved to Last Call. This move has brought a whole host of syntax changes, and we have updated the Blink and WebKit implementations accordingly. Read on for a summary of what has changed in the specification.
Note on the examples
If you wish to view the examples live on CodePen when reading this article, you need to get a browser that supports CSS Shapes and make sure they are enabled. If that sounds interesting, take a look at our browser support page, which will tell you which browsers support Shapes and how to enable it.
You can now define shapes based on the CSS Box Model of the element the shape applies to. The shape can be declared as the
content-box. This shape conforms to any
border-radius that has been specified on the element. And if you would like to take a look at CodePen, there is an example of the box values being used as shapes.
Basic Shapes with box values
You can also specify a box value along with a basic shape. This box value is referred to as the reference box for the shape. This causes the basic shape to use that box instead of the default box to determine things like sizing and position of the shape. The default box depends on which property you are setting the value for:
shape-outside defaults to
clip-path defaults to
border-box. For example, the following two properties could define entirely different circles depending on the margin, padding, or border that is applied to the element:
shape-outside: circle(); shape-outside: circle() content-box;
If you don’t understand the use of
circle() here, don’t worry. The next section covers all of the shapes and the changes that apply to them.
Basic shapes are at the core of the CSS Shapes module. Most of the shapes have been changed from a SVG-style syntax to one more in line with other CSS properties. With the exception of
polygon, all other shapes have undergone significant alterations.
rectangle and inset-rectangle are now inset
A single shape,
inset, has replaced the
inset-rectangle shapes. This shape defines a rectangle with sides that are inset from the sides of the reference box by a given amount.
Basic inset syntax
The basic syntax for inset is like that of the margin shorthand. If you supply one argument, then that argument specifies the inset for all four sides of the rectangle:
If you specify two arguments, the first argument specifies the inset for the top and bottom, while the second argument specifies the inset for the right and left:
You can also specify three arguments, where the first argument specifies the inset for the top, the second argument specifies the inset for the right and left, and the third argument specifies the inset for the bottom:
inset(top right_left bottom)
Finally, you can specify four arguments, in which case, each argument specifies the inset for a different side, like so:
inset(top right bottom left)
There are some live examples of inset with different arguments on CodePen.
Rounding the corners
It doesn’t stop there! You can take any of the forms above and add the
round keyword and then use the familiar border-radius syntax to define rounded corners for the resultant rectangle. A very simple example:
inset(30% round 10%)
Of course you can do more complex things:
inset(10% round 10% 40% 10% 40%)
You can see the following more complex inset shape examples live on CodePen.
circle and ellipse – same names, different arguments
ellipse are still with us. However, the arguments they take have changed significantly.
How to specify radii
To start, radii are no longer exclusively lengths or percentages. There are two new keywords that can be used to define the radii:
farthest-side. Both of these keywords refer to the distance from the center of the shape to a side of the reference box.
closest-side uses the distance from the center of the shape to the side of the reference box that is closest to the center coordinate of the shape. In the case of a circle, this is as simple as measuring the distance between the center of the circle and each side of the reference box and using the minimum distance. It is a little more complex in the case of an ellipse, since the ellipse has two radii: one in the horizontal direction (rx), and one in the vertical direction (ry). To compute the
closest-side value for an ellipse, only the sides in the direction of the radius in question are considered. For example, to find the closest side for ry, you would only compare the distances between the center and the two sides in the vertical direction.
circle() is the same as
circle(closest-side), which defines the largest circle that will fit within the reference box. And
ellipse() is equivalent to
ellipse(closest-side closest-side), defining the largest ellipse that will fit within the referemce box. You can see the following example of circles and ellipses defined with closest-side live on CodePen.
farthest-side is analogous to
closest-side, it just looks for the distance to the side of the reference box that has the largest distance from the shape’s center. Just like with all of the previous examples, you can see the following circle defined with farthest-side on CodePen.
How to define the center
It isn’t just radii that have changed. You now can use the full CSS position syntax to define the center of the shape. This is done by including the
at keyword and following that with a
position, like so:
circle(closest-side at center)
And yes, this example of a positioned circle is available on CodePen.
circle(). That is because this is the full expansion of that shorthand. Note that
circle(at center)is yet another way to say the same thing. All of the arguments are optional, and they all have defaults.
You can of course position an
circle at a different point than the center. It is beyond the scope of this article to cover all of the options here, but I can give a few examples.
ellipse(at top 50% left 20%) circle(25% at 25% 50%)
If you would like to play with this or see it in action, you can check out the positioned ellipse and circle example on CodePen.
How do I use these shapes?
The CSS Shapes specification defines a
shape-outside directive that changes the wrapping behavior of floats so that content can wrap around an arbitrary shape. All of the examples in the previous sections use
shape-outside. In addition, these shapes can be used with the
clip-path property, from the CSS masking specification. If you look closely at all of the examples used in this article, they all use the
clip-path property to visualize the shape.
This article has just covered some of the largest changes that have come with the move to Last Call. Future blog posts will cover use of these shapes and the other shapes types defined in CSS Shapes in more detail. If you can’t wait, you can always take a look at the CSS Shapes specification for the authoritative take.