The CSS Shapes Level 1 Specification describes geometric shapes in CSS. They are, in Level 1 of the specification, designed to be applied to floated items. This article provides an overview of what you can do with shapes.
You could for example float an item left, which would cause the text to wrap round the right and bottom of the item in a rectangular fashion. If you then apply a circle shape, the text would then wrap round the line of the circle.
There are a number of ways to create these Shapes and in these guides we will find out how CSS Shapes work, and consider some ways you might like to use them.
What does the specification define?
The specification defines three new properties:
shape-outside— allows definition of basic shapes
shape-image-threshold— Sets an opacity threshold value. If an image is being used to define the shape, only the parts of the image that are the same opacity or greater than the threshold value are used in the shape. Any other parts are ignored.
shape-margin— sets a margin around the defined shape
Defining basic shapes
shape-outside property allows us to a define a shape. It takes a variety of values, all of which define different shapes, specified in the
<basic-shape> datatype. We can start by looking at a very simple case.
In the following example I have an image floated left. I have then applied the
shape-outside property to it with a value of
circle(50%). The result is that the content now curves around the circular shape rather than following the rectangle created by the box of the image.
As in this level of the specification an element has to be floated in order to apply
<basic-shape> to it; this has the side-effect of creating a simple fallback for many cases. If you do not have Shapes support in the browser, the user will see content flowing around the sides of a rectangular box as before. If they do have Shapes support then the visual display is enhanced.
circle(50%) is an example of a Basic Shape. The specification defines four
<basic-shape> values, which are:
Using the value
inset() wraps text around a rectangular shape however you are able to add offset values, thus pulling the line boxes of any wrapping content closer to the object than would otherwise happen.
We have already seen how
circle() creates a circular shape. An
ellipse() is essentially a squashed circle. If none of these simple shapes do the trick you can create a
polygon() and make the shape as complex as you want.
In our Guide to Basic Shapes we explore each of the possible Basic Shapes and how to create them.
Shapes from the Box Value
Shapes can also be created around the Box Value, therefore you could create your shape on the:
In the example below you can change the value
border-box to any of the other allowed values to see how the shape moves closer or further away from the box.
To explore the box values in more detail see our guide covering Shapes From Box Values.
Shapes from images
An interesting way to generate your path is to use an image with an alpha channel — the text will then wrap around the non-transparent parts of the image. This allows the overlay of wrapped content around an image, or the use of an image which is never displayed on the page purely as a method of creating a complex shape without needing to carefully map a polygon.
Note that images used in this way must be CORS compatible, otherwise
shape-outside will act as if
none had been given as the value, and you will get no shape.
In this next example, we have an image with a fully transparent area, and we are using an image as the URL value for
shape-outside. The shape is created around the opaque area — the image of the balloon.
shape-image-threshold property is used to set the threshold of image transparency used to define the area of the image used for the shape. If the value of
0.0 (which is the initial value) then the area must be fully transparent. If the value is
1.0 then it is fully opaque. Values in between mean that you can set a semi-transparent area as the defining area of the shape.
You can see the threshold in action if we use a gradient as the image on which to define our shape. In the example below, if you change the threshold the path that the shape takes changes based on the level of opacity you have selected.
We take a deeper look at creating shapes from images in the Shapes from Images guide.
shape-margin property adds a margin to
shape-outside. This will further shorten the line boxes of any content wrapping the shape, pushing it away from the shape itself.
In the example below we have added a
shape-margin to a basic shape. Change the margin to push the text further away from the path the shape would take by default.
Using Generated Content as the floated item
In the examples above we have used images or a visible element to define the shape, meaning that you can see the shape on the page. Instead, you might simply want to cause some text to flow along a non-rectangular invisible line. You can do this with Shapes, however you will still need a floated item, which you can then make invisible. That could be a redundant element inserted into the document, an empty
<span> perhaps, but our preference is to use generated content. This means we can keep things used for styling inside the CSS.
In this next example, we use generated content to insert an element with height and width of 150px. We can then use Basic Shapes, Box Values or even the Alpha Channel of an image to create a shape for the text to wrap around.
The Basic Shapes and Box values used to create Shapes are the same as those used as values for
clip-path. Therefore if you want to create a shape using an image, and also clip away part of that image, you can use the same values.
The image below is a square image with a blue background. We have defined a shape using
shape-outside: ellipse(40% 50%); and also used
clip-path: ellipse(40% 50%); to clip away the same area that we have used to define the shape.
Developer Tools for Shapes
Along with CSS Shapes support in the browser, Firefox are shipping a Shape Path Editor in the Firefox DevTools. This tool means that you can inspect any shapes on your page, and even change the values in the live page. If your polygon isn’t quite right you can use the Shapes Editor to tweak it, then copy the new value back into your CSS.
The Shape Path Editor will be enabled by default in Firefox 60 for shapes generated via
clip-path. You can also use it to edit shapes generated via
shape-outside, but only when you enable it via the
Future CSS Shapes Features
The initial Shapes specification included a property
shape-inside for creating shapes inside an element. This property, along with the possibility of creating shapes on non-floated elements, has been moved to level 2 of the specification. As the
shape-inside property was initially in Level 1 of the specification, you may find tutorials on the web detailing both properties.