With modern web layout you can have your content laid out in whatever shape you want as long as it’s a rectangle. Designers in other media have long been able to have text and other content lay out inside and around arbitrarily complex shapes. The CSS Exclusions and Shapes specification aims to bring this capability to the web.
While these features aren’t widely available yet, implementation is progressing and it’s already possible to try out some of the features yourself. Internet Explorer 10 has an implementation of the exclusions processing model, so you can try out exclusions in IE 10 today.
At Adobe we have been focusing on implementing the shapes portion of the specification. We began with an implementation of shape-inside and now have a working implementation of the shape-outside property on floats. We have been building our implementation in WebKit, so the easiest way to try it out yourself is to download a copy of Chrome Canary. Once you have Canary, enable Experimental WebKit Features and go wild!
What is shape-outside?
“Now hold up there,” you may be thinking, “I don’t even know what a shape-outside is and you want me to read this crazy incomprehensible specification thing to know what it is!?!”
Well you’ll be happy to know that it really isn’t that complex, especially in the case of floats. When an element is floated, inline content avoids the floated element. Content flows around the margin box of the element as defined by the CSS box model. The shape-outside CSS property allows you to tell the browser to use a specified shape instead of the margin box when wrapping content around the floating element.
The current implementation allows for rectangles, rounded rectangles, circles, ellipses, and polygons. While this gives a lot of flexibility, eventually you will be able to use a SVG path or the alpha channel of an image to make it easier to create complex shapes.
How do I use it?
First, you need to get a copy of Chrome Canary and then enable Experimental WebKit features. Once you have that, load up this post in Chrome Canary so that you can click on the images below to see a live example of the code. Even better, the examples are on Codepen, so you can and should play with them yourself and see what interesting things you can come up with.
Note that in this post and the examples I use the unprefixed shape-outside property.
If you want to test these examples outside of my Codepen then you will need to use the prefixed -webkit-shape-outside property or use (which is a built in option in Codepen).
We’ll start with a HTML document with some content and a float. Currently shape-outside only works on floating elements, so those are the ones to concentrate on. For example: (click on the image to see the code)
You can now add the shape-outside property to the style for your floats.
.float {
shape-outside: circle(50%, 50%, 50%);
}
A circle is much more interesting than a standard rectangle, don’t you think? This circle is centered in the middle of the float and has a radius that is half the width of the float. The effect on the layout is something like this:
While percentages were used for this circle, you can use any CSS unit you like to specify the shape. All of the relative units are relative to the dimensions of element where the shape-outside is specified.
Supported shapes
Circles are cool and all, but I promised you other shapes, and I will deliver. There are four types of shapes that are supported by the current shape-outside implementation: rectangle, circle, ellipse, and polygon.
rectangle
You have the ability to specify a shape-outside that is a fairly standard rectangle:
shape-outside: rectangle(x, y, width, height);
The x and y parameters specify the coordinates of the top-left corner of the rectangle. This coordinate is in relation to the top-left corner of the floating element’s content box. Because of the way this interacts with the rules of float positioning, setting these to anything other than 0 causes an effect that is similar to relatively positioning the float’s content. (Explaining this is beyond the scope of this post.)
The width and height parameters should be self-explanatory: they are the width and height of the resulting rectangle.
Where things get interesting is with the six-argument form of rectangle:
shape-outside: rectangle(x, y, width, height, rx, ry);
The first four arguments are the same as explained above, but the last two specify corner radii in the horizontal (rx) and vertical (ry) directions. This not only allows the creation of rounded rectangles, you can create circles and ellipses as well. (Just like with [border-radius][border-radius].)
Here’s an example of a rectangle, a rounded rectangle, a circle, and an ellipse using just rectangle syntax:
If you’re reading this in Chrome Canary with exclusions turned on, play around with this demo and see what other things you can do with the rectangles.
circle
I already showed you a simple circle demo and you’ll be happy to know that’s pretty much all there is to know about circles:
shape-outside: circle(cx, cy, radius);
The cx and cy parameters specify the coordinates of the center of the circle. In most situations you’ll want to put them at the center of your box. Just like with rectangles moving this around can be useful, but it behaves similarly to relatively positioning the float’s content with respect to the shape.
The radius parameter is the radius of the resulting circle.
In case you’d like to see it again, here’s what a circle looks like:
While it is possible to create circles with rounded rectangles as described above, having a dedicated circle shape is much more convenient.
ellipse
Sometimes, you need to squish your circles and that’s where the ellipse comes in handy.
shape-outside: ellipse(cx, cy, rx, ry);
Just like a circle, an ellipse has cx and cy to specify the coordinates of its center and you will likely want to have them at the center of your float. And just like all the previous shapes, changing these around will cause the float’s content to position relative to your shape.
The rx and ry parameters will look familiar from the rounded rectangle case and they are exactly what you would expect: the horizontal and vertical radii of the ellipse.
Ellipses can be used to create circles (rx = ry) and rounded rectangles can be used to create ellipses, but it’s best to use the shape that directly suits your purpose. It’s much easier to read and maintain that way.
Here’s an example of using an ellipse shape:
polygon
Now here’s where things get really interesting. The polygon `shape-outside` allows you to specify an arbitrary polygonal shape for your float:
shape-outside: polygon(x1 y1, x2 y2, ... , xn yn);
The parameters of the polygon are the x and y coordinates of each vertex of the shape. You can have as many vertices as you would like.
Here’s an example of a simple polygon:
Feel free to play with this and see what happens if you create more interesting shapes!
Putting content in the float
The previous examples all had divs without any content just to make it easier to read and understand the code, but a big motivation for shape-outside is to wrap around other content. Interesting layouts often involve wrapping text around images as this final example shows:
As usual, you should take a look and play with the code for this example of text wrapping around floated images. This is just the beginning of the possibilities, as you can put a shape outside on any floating element with any content you want inside.
Next steps
We are still hard at work on fixing bugs in the current implementation and implementing the rest of the features in the CSS Exclusions and Shapes specification. We welcome your feedback on what is already implemented and also on the spec itself. If you are interested in becoming part of the process, you can raise issues with the current WebKit implementation by filing bugs in the WebKit bugzilla. If you have issues with the spec, those are best raised on the www-style mailing list. And of course, you can leave your feedback as comments on this post.
I hope that you enjoy experimenting with shape-outside and the other features we are currently working on.