Adobe

decor

Web Platform Team Blog

Making the web awesome

New CSS Shapes Syntax

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.

Box values

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 margin-box, border-box, padding-box, or 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.

box values example

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 margin-box, while 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

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 rectangle and 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:


inset(value)

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:


inset(top_bottom right_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.

inset examples

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.

inset with rounded corners example

circle and ellipse – same names, different arguments

Both circle and 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: closest-side and 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

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.

For example, 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.

circle and ellipse example

farthest-side

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.

circle farthest-side example

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.

positioned circle example
If you read the previous section, you might realize that the result looks exactly the same as the example for 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 ellipse or 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.

positioned circle and ellipse example

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.

Further reading

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.

2 Comments

  1. February 17, 2014 at 2:14 pm, Jeniv said:

    I think this code is just suport on webkit based browser, isn’t it?

    • February 18, 2014 at 8:18 am, Bem Jones-Bey said:

      It’s only supported in WebKit Nightly and Chrome Canary at the moment. (Chrome uses a fork of WebKIt (Blink), and it is rapidly diverging from WebKit)