CSS Reference Property

shape-outside

The shape-outside property is used to change the geometry of a float element‘s float area.

Changing an element’s float area means changing the way the content flows around the floating element. Every element on a web page is rectangular, and is seen as a rectangle by every other element on the page. So, even if you change the shape of an element by rounding it, for example, using border-radius, the content around the element will still flow as if the element is rectangular, not circular. Using shape-outside, you can change that, allowing content to wrap around a specified shape, instead of having it wrap around the old rectangular one.

For example, the following image shows an image that has been rounded using the border-radius property. It shows how the text flows around it without using shape-outside to change the float area, and then with using it.

with-without-shape-outside
Image showing the result of applying shape-outside to a rounded image and how it changes the flow of content around it.

The shape-outside property takes a <basic-shape> as a value. The basic shape is defined using a shape function, and is used to change the shape of the float area of the element.

The shape-outside property also accepts an image URI as a value. The URI should point to an image with alpha transparency. The browser will then extract the shape from the image and use it to change the float area of the element. Using an image, you can even define multiple shapes on an element, as the browser will extract all the shapes inside the image. You can’t define multiple shapes using shape functions; you can, however, do it using an image.

Prerequisites – Conditions That Need to be met in order for shape-outside to work

In order for the shape-outside property to work, these two conditions must be met:

  • The element must be floated. The element whose float area you’re changing must be a float. Future levels of CSS Shapes may allow us to define shapes on non-floated elements, but that is not yet possible.
  • The element must have intrinsic dimensions. The height and width set on an element will be used to establish a coordinate system on that element.

A coordinate system needs to be established in order for the shape-outside property to work. The reason behind this is that the <basic-shape>s used are defined by a set of points. These points are passed to the shape functions in the form of coordinate pairs. Because these points have coordinates, a coordinate system is necessary for the browser to know where to position each point on the element.

A Shape’s Reference Box

In addition to the basic shape function, the shape-outside property accepts a keyword that defines a shape’s reference box. The keyword defining the reference box can be used either on its own or in conjunction with a basic shape function.

A reference box is the box used to draw the shape on the element. In addition to the element’s height and width, the element’s box model boxes—margin box, content box, padding box, and border box—are also used as a reference to specify the extent of the shape on an element.

By default, the margin box is used as a reference—so, if an element you want to apply a shape to has a margin at the bottom, the shape you define on the element will extend to the edges of the margin area, not the element’s border area. If you want to use one of the other box values, you can specify it in conjunction with the shape function that you pass to the shape properties.

The following is a simple example defining a circular shape, and specifying the reference box along with it:

shape-outside: circle(15em at 10% 40%) padding-box;
                

The above code sample will define a circular shape on the element, within the bounds of the element’s padding area.

Trivia & Notes

Shapes applied to an element that has background images

Sometimes, defining a shape on an element and changing its float area isn’t enough to achieve the effect you may be after.

For example, suppose you have an element that has a background image, and you change the float area of the element using shape-outside. The content around the element floats around the shape you defined. All is good so far. However, one important thing to note at this point is that the shape property does not change anything about an element other than its float area. This means that any borders and background images will not adapt to the shape created on the element. So, even though the element’s float area changes, the content around the element may end up being on top of the element’s background image.

The following image shows an image that is a background image of an element with a triangular shape applied to it. The content flows around the shape as expected. However, the background image of the element remains rectangular because it is not affected by the shape-outside property.

with-without-shape-outside-background
Illustration showing an image that is a background image of an element with a circular shape applied to it.

In order “clip” the background of the element to match the defined shape, you can make use of a very useful CSS property from the CSS Masking module: the clip-path property.

The clip-path property can be used to literally clip parts of the element that we don’t need and keep only the parts inside the shape we defined. This is possible because of the fact that the clip-path property can take the same basic shape values as the shape-outside property, and also because the user coordinate system for the shapes defined by the clip-path property can be established using the same reference box used by the shape-outside property, so the two properties can use the same coordinate system, the same reference box, and the same shape functions.

If we were to recreate the example in the above image, and use the clip-path property to clip the element to the triangular shape, the CSS would look something like this:

.element {
    float: left; 
    width: 150px;
    height: 150px;
    shape-outside: polygon(50% 0%, 100% 100%, 0% 100%);
    clip-path: polygon(50% 0%, 100% 100%, 0% 100%);
}
                

Clipping the element’s background and border areas to the same shape used on the float area gives the following result:

after-using-clip-path
Image showing the result of applying clip-path with shape-outside to clip the background image of a shaped element.

The clip-path property is an excellent companion to the CSS Shapes properties, so you’re likely going to find yourself using them together a lot.

Animating Shapes

There are two ways you can define a shape on an element using the shape-outside property: using shape functions, or an image URI (See the Values section below for details.).

Shapes defined using an image are not animatable. So, if you define a shape using an image, specify a transition, and then define another shape using another image when the element is hovered, for example, the shape applied to the shape will change but it will not animate or transition into the new shape; it will just “jump” from one shape into another in an abrupt manner.

A CSS Shape can be animated, however, if it is defined using a shape function. A shape function, as mentioned earlier, takes a set of points as values that are make up the shape. These points are defined by coordinate pairs. Coordinates are either length values, or percentage values. Both lengths and percentages can be interpolated and hence are animatable. So the transitions on CSS shapes are really transitions on the individual points making up a shape. More specifically, transitions on the coordinates of each point, where the coordinates are interpolated as real numbers to allow animations and transitions, just like any other animatable CSS values.

With that said, there is one condition that has to be met in order for shapes to be animatable: If you’re animating from one shape to another, the number of points defining the final shape must be the same as the number of points defining the initial shape.

There’s a lot that can be said about animating CSS Shapes that is outside the scope of this entry. For more information on this topic, refer to this article about Animating CSS Shapes with CSS animations and transitions.

Accessibility

There are certain things to consider before animating CSS shapes and even before choosing the shapes to change the float areas of elements.

  • If you’re animating CSS shapes, keep in mind that the content that fits into one shape may not perfectly fit into another. You may start out with a simple shape, and when you animate that shape into a new one, the content inside that shape may overflow the new shape, or may be too little for the new shape. So you may need to resize the element as you change its shape as well, so, the design has to be thought through in detail. This also means that it wouldn’t be very simple to depend on animated CSS shapes for dynamic content, unless you create the shapes dynamically with Javascript.
  • Animating text composition in general, whether by animating Shapes or even a simple animation of width, will make the text temporarily unreadable. The process of text changing its layout blocks the ability of the reader to read your content, and it is only after the animation is over that they will again be able to read the text.
  • If you’re using an image to define a shape, you will be able to define multiple shapes inside that image (see the Values and Examples sections below), and those shapes can be used to modify the float area. Multiple shapes, or shapes that are too complex, can cause readability problems and can render the text completely illegible to some people. Choose shapes that do not affect the readability of the text in a bad way, and it never hurts to test and ask people to read the content after the shape has been applied, because what may seem readable to a designer, may not always be readable to other people.

Official Syntax

  • Syntax:

    shape-outside: none | [ <basic-shape> || <shape-box> ] | <image>
                           
  • Initial: none
  • Applies To: floats
  • Animatable: as specified for <basic-shape>, otherwise no

Values

none
No shape is applied. The element’s float area is not affected.
<shape-box>
Can be one of the four box model values: margin-box, border-box, padding-box, content-box. If one of these values is specified by itself the shape is computed based on one of margin-box, border-box, padding-box, or content-box, which use their respective boxes including curvature from border-radius, similar to background-clip.

This value can be used on its own, or in conjunction with a <basic-shape> function. If it is used in conjunction with a shape function, it is used as a reference box to specify the extent of the shape on an element.

<basic-shape>
The shape is computed based on the values of one of inset(), circle(), ellipse() or polygon(). If a <shape-box> is also supplied, this defines the reference box for the <basic-shape> function. If <shape-box> is not supplied, then the reference box defaults to margin-box.

See the <basic-shape> entry for more information about this value and a detailed description of the shape functions.

<image>
A URI to an image. The image is one with an alpha channel. The shape is extracted and computed based on the alpha channel of the specified <image> as defined by shape-image-threshold property. The shape is defined by the pixels whose alpha value is greater than the threshold.

The image must be CORS compatible. If the image provided cannot be displayed for any reason (such as if it doesn’t exist), then no shape will be applied.

Using an image, multiple shapes can be defined. The following is an example of an image with an alpha channel (a PNG image with transparent and opaque areas) that contains more than one shape.

multiple-shapes

The text will flow where the image is transparent. Black areas represent the shape where the content will not be able to flow; i.e the shape that the content will flow around.

Usually, when the shape you want to define is too complex for a basic shape function, you’re better off using an image. For example, if the shape contains many curvatures, too many points, etc.

Note that there is no current way to position a shape image inside an element. This means that, if the image is smaller or bigger than the element you’re using it on, the shape may not end up as you expect. In most cases, for the time being, you’re going to want to use the same image size as the size of the element. The image will, by default, be centered inside the element.

Examples

Example #1

We’re going to start with a simple example. We have an element floated to the left, with a cupcakes background. The element gets a circular shape using the circle() function. Only thing to notice here is that the circle is given a big radius and positioned on the left edge of the element, so achieve the effect shown in the following screenshot of the demo:

cupcake-example
Screenshot of example #1.

We’re also going to use the shape-margin property to add some margin to the right of the element, to push the text on the right a little bit away from the shape.

Last but not least, we’re using the clip-path property with the same shape definition as that used in the shape-outside property, in order to clip the background of the element to the circular shape.

.element {
    width: 60vw;
    height: 100vh;
    float: left;
    background-image: url(cupcakes.png);
    background-size: cover;

    clip-path: circle(70% at 0% 50%);
    shape-outside: circle(70% at 0% 50%) border-box;

    shape-margin: 2em;
}
                

See the Live Demo section below for a live example.

Example #2

In our second example, we have an element that has a background image of a teddy bear with a cup of coffee. What we want to do is wrap the text around the bear and the cup of coffee, while also have the text be displayed over the image.

bear-example
Screenshot of the example #2.

The way we’re going to achieve that is:

  • Define the shape we need so that the text floats around the bear and the cup.
  • Because we want the text to be displayed on the image, we’re going to size the element so that it has the same size as the container. As a matter of fact, we’re doing the opposite: size the container so that it’s as big as the element inside it.
  • The second step, combined with the first, will automatically have the text occupy the shaped flow area of the shaped element.

The markup is simple:

<div class="container">
    <div class="element"></div>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur, earum, cum cumque ullam tempora quos expedita officiis consectetur! Tenetur aliquam error doloribus praesentium facilis delectus autem temporibus iusto ad dignissimos?</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consequuntur, earum, cum cumque ullam tempora quos expedita officiis consectetur! Tenetur aliquam error doloribus praesentium facilis delectus autem temporibus iusto ad dignissimos?</p>
</div>
                

In the CSS, the element with the bear background is going to be floated to the right. The container will have the same dimensions as the element. The paragraphs will just flow in the element’s flow area!

Now, in order to define a shape that defines the float area based on the teddy bear and cup of coffee, you can either use an image, or draw the shape using the polygon() function. In our case, we’ve used the Shapes editor extension (see the Tools note section below) to create the shape using the function.

.container {
    width: 800px;
    /* clear floats */
    overflow: hidden;
    /* other styles here.. */
}
.element {
    /* establish coordinate system */
    width: 800px;
    height: 600px;
    /* float the element */
    float: right;
    background-image: url(bear.jpg);
    background-size: cover;
    /* apply shape and specify reference box */
    shape-outside: polygon(nonzero, 23% 89.85%, 23.75% 83.85%, 27.75% 78.35%, 33.75% 75.15%, 42.65% 75.65%, 46.25% 69.35%, 51.65% 68.15%, 52.65% 61.65%, 55.65% 54.15%, 42.5% 37.85%, 42.9% 29.15%, 46.25% 24.35%, 51.25% 23.65%, 53.65% 13.15%, 59.25% 5.65%, 68% 1%, 99.75% 0.65%, 100% 100%, 23.9% 99.85%) border-box;
} 
                

We could have used an image with an alpha channel similar to this one to get the same result:

bear-shape

The shape would then have been defined like so:

.element {
    ...
    shape-outside: url(bear-shape.png) border-box;
}
                

The following image shows the above example, with the polygonal shape and its corresponding points highlighted.

bear-example-shape
Image showing the polygonal shape applied to the element.

You can check this example out live in the Live Demo section below.

Notes: Tools For CSS Shapes

Creating complex shapes using Shapes functions can be a daunting task, especially if you’re creating one with many points and coordinates for the polygon() function. However, there are a couple of tools that can help you create basic shapes with much ease. One of these tools is the Shapes Tools collection by Bear Travis from Adobe. These tools allow you to create polygonal shapes visually. The tool then generates the shape function for us.

A more advanced and interactive tool is the Shapes Editor Extension created for Adobe’s Brackets editor. It allows you to visualize and edit shapes directly in the browser, and has a live preview feature that updates the shape values in the stylesheet as you change them on the page. This gives you instant visual feedback for your changes, allowing you to see how your shapes interact with other elements on the page.

shapes-editor

The images in the previous example showing the polygonal shape applied to the element with its points highlighted has been captured while using the Shapes editor. It’s a great tool and you’re going ot love using it when you’re working with/editing CSS Shapes.

For more information on how to get this tool and use it, read this article on the Brackets blog.

Live Demo

Example #1 Live Demo

View this demo on the Codrops Playground

Example #2 Live Demo

View this demo on the Codrops Playground

Live Demo #3

The following example shows an element with a background floated to the left, with text wrapping on its side. The shape is created using a shape function.

Try changing the shape function value, shape points, and playing with the code to see how the shape adjusts and changes accordingly.

View this demo on the Codrops Playground

Browser Support

CSS Shapes Level 1

Allows geometric shapes to be set in CSS to define an area for text to flow around. Includes properties `shape-outside`, `shape-margin` and `shape-image-threshold`

W3C Candidate Recommendation

Supported from the following versions:

Desktop

  • 37
  • 62
  • No
  • 24
  • 10

Mobile / Tablet

  • 10
  • 122
  • No
  • 122
  • 123

* denotes prefix required.

  • Supported:
  • Yes
  • No
  • Partially
  • Polyfill

Stats from caniuse.com

Written by . Last updated December 11, 2016 at 10:48 pm by Manoela Ilic.

Do you have a suggestion, question or want to contribute? Submit an issue.