The CSS Shapes Module — Breaking Out of the Box

One of the limitations of developing websites is that everything is fundamentally a rectangular box. We fight against it. We create non-rectangular images, we round corners, we have a variety of creative techniques to display less box-like shapes, but still behind the scenes each of these things sits in a rectangular box and other elements react to that box seen or unseen.

The above won’t be the case forever. One of the W3C specs that’s getting talked about recently in designer and developer circles is the CSS Shapes Module.

Before I get too far into this post, please know that CSS Shapes is a level 1 working draft module and it’s not something you’re going to be using in production any time soon. It’s possible that much of what I detail here will even change by the time you can.

Normally I prefer to wait until something is closer to being production ready to talk about it here. However, this spec has the potential to completely free us from always having to use rectangles and that possibility should excite you.

graphic showing how text wraps around a css shape
How text wraps around a css shape defined by an image

Browser Support

Let’s start with the bad news. What kind of browser support do CSS Shapes have right now? Not much at all. There are currently two options for getting css shapes to work and those are Chrome Canary and Webkit Nightly, neither of which is meant to replace your every day browser.

If you don’t have either currently installed, grab one or both. Click on the link above for instructions on setting the correct flag in Canary. Webkit should work out of the box. I’ve only used Chrome Canary myself so far and can’t say for certain how everything below works in Webkit Nightly, but I have no reason to doubt that it works the same way.

What are CSS Shapes?

These aren’t shapes created by rounding corners, getting creative with borders, or making use of before and after pseudo elements. Those look like shapes to us, but other elements on the page see them as the rectangular boxes that they really are.

If you’re interested in the above kind of shapes you can find details in the following posts and many others can be easily found with a bit of searching.

The css shapes in the new spec are different. The major change is that other elements won’t automatically see a rectangular box and will flow around the shape created. With just a few css properties we’ll be able to turn rectangular boxes into geometric shapes that allow inline content to flow around them.

In the first level of the spec it’s only applied to floated elements, but future levels of the spec will include non-floated elements as well.

This really opens up the potential for how we can design websites. Not that I expect rectangular boxes to ever go away, but being able to use other shapes fundamentally changes things.

It’s important to note the box model itself isn’t changing. The element is still contained inside a rectangular box defined, by width, height, paddings, borders, and margins. What’s changing is how other elements can wrap around them.

Five shapes are currently supported

  • rectangle
  • inset-rectangle
  • circle
  • ellipse
  • polygon

Each is defined using syntax similar to the the basic shapes of SVG and you can additionally define shapes from the alpha channel of a source image.

Working with CSS Shapes

It’s hard to know how much of this will change, but for now we’re dealing with just a few properties and they’re relatively easy to understand.

  • shape-outside
  • shape-inside
  • shape-margin
  • shape-padding
  • shape-image-threshold

At the moment you’ll need to use the -webkit vendor prefix to get these to work in both Canary and Webkit, though I suspect in time Canary will drop the prefix.

The first two properties are used to declare the 5 supported shapes mentioned in the section above.

[code type=css]
-webkit-shape-outside: rectangle(x, y, width, height);
-webkit-shape-outside: rectangle(x, y, width, height, rx, ry);
[/code]

x and y are coordinates for the top-left corner of the rectangle, relative to the top-left corner of the element’s container. Width and height are just what you think and rx and ry are for setting radii to round the corners.

[code type=css]
-webkit-shape-outside: circle(cx, cy, radius);
-webkit-shape-outside: ellipse(cx, cy, rx, ry);
[/code]

cx and cy are coordinates for the center of the circle or ellipse, again relative to the element’s container. With circles a single radius is set and with ellipse, both horizontal and vertical radii are set.

[code type=css]
-webkit-shape-outside: polygon(x1 y1, x2 y2,…, xn yn);
[/code]

The polygon can take as many x and y coordinate values as you want to give it. Again each is relative to the container. Set 3 points and you’ll have a triangle, set 4 points you have a rectangle and so on.

Trying to figure out all the different coordinates for more complex shapes probably isn’t the most fun thing you can do, but have no fear. You can use tools like Poly Draw to figure the coordinates out for you.

The shape-inside property works the same way, except, as the name implies, it affects what’s inside the element’s border as opposed to outside. The spec mentions it will be defined in a future version, but it works now in Chrome Canary and Webkit-Nightly.

[code type=css]
-webkit-shape-padding: 20px;
-webkit-shape-margin: 2em;
[/code]

Both shape-padding and shape-margin take a single length value that is used as the padding or margin over the entire shape and is perpendicular to the shape at every point. Each can be used on any of the supported shapes.

[code type=css]
-webkit-shape-image-threshold: 0.5;
[/code]

I haven’t yet experimented with the shape-image-threshold, but the idea is it gets a value between 0.0 and 1.0. A value of 0.5 means that all pixels more than 50% transparent in the image are used to define the path of the shape. Naturally you’ll need to use images with transparency so .pngs or .gifs and not .jpgs.

Examples

Since support is so limited I didn’t create a demo for you to view. Instead I played around locally and captured some screenshots. I’ve added the code I used for each example so you can recreate them.

One thing that tripped me up at first was trying to set a background color on the shapes. The background fills the rectangular box defined by the box-model. Borders do the same. They didn’t follow the shape as I expected they might. Perhaps at some point in the future that will change.

Aside: For the literary minded among you, the text in all examples is the opening from Jack Kerouac’s On the Road. I didn’t show the text in the html snippets below to save some space.

Example 1

This first example is simply a circle shape floated to the left. I gave the shape a background color and a border so you can see how the box model is still at work. However, you can see the text flows around a circular shape.

Text wrapping a css circle

[code type=html]

[/code]

[code type=css]
.float-left {
width: 100px;
height: 100px;
float: left;
-webkit-shape-inside: circle(50%, 50%, 50%);
-webkit-shape-outside: circle(50%, 50%, 50%);
-webkit-shape-margin: 50px;
-webkit-shape-padding: 50px;
background: #ccc;
border: 1px solid red;
}
[/code]

Example 2

The text below wraps around two triangles, one floated left and the other floated right. On the right you can see the borders around each. Both triangles were created using the polygon shape and specifying 3 points.

Triangle created by having text flow around two triangular css shapes

[code type=html]

[/code]

[code type=css]
.float-left {
width: 100px;
height: 600px;
float: left;
-webkit-shape-inside: polygon(0 0, 0 100%, 100% 100%);
-webkit-shape-outside: polygon(0 0, 0 100%, 100% 100%);
-webkit-shape-margin: 50px;
-webkit-shape-padding: 50px;
}

.float-right {
width: 100px;
height: 600px;
float: right;
-webkit-shape-inside: polygon(100% 0, 100% 100%, 0 100%);
-webkit-shape-outside: polygon(100% 0, 100% 100%, 0 100%);
-webkit-shape-margin: 50px;
-webkit-shape-padding: 50px;
}
[/code]

Example 3

The circular text below is formed using only shape-inside. I’m not sure why, but no matter what text is used, the first line always defaults to using a single word.

Text circle created with shape-inside

[code type=html]

[/code]

[code type=css]
p {
width: 475px;
height: 460px;
margin: 0px auto;
-webkit-hyphens: auto;
-webkit-shape-inside: circle(50%, 50%, 50%);
text-align: justify;
}
[/code]

Example 4

Similar to the example above, the text here is shaped using shape-inside, though this time as a polygon. I didn’t try to calculate all the points. I used the Poly Tool I mentioned above to create the shape and then copied the points for the polygon.

Text polygon created with shape-inside

[code type=html]

[/code]

[code type=css]
p {
width: 500px;
height: 725px;
margin: 0px auto;
-webkit-hyphens: auto;
-webkit-shape-inside: polygon(26.42% 23.00%,25.27% 33.09%,21.12% 42.93%,17.24% 51.85%,14.35% 62.28%,15.09% 82.32%,22.83% 93.37%,72.92% 92.87%,66.65% 82.28%,66.38% 65.43%,69.23% 54.09%,74.08% 43.75%,77.29% 32.91%,77.50% 22.57%,72.42% 6.63%,20.83% 2.88%);
text-align: justify;
}[/code]

Mine are hardly the only examples of css shapes online. Here are some examples others have created for additional inspiration and explanation.

Summary

Once again this isn’t anything you can use in production at the moment, though it seems like browser makers are on board and progressing in their implementation. You can experiment now in Chrome Canary and Webkit Nightly..

I don’t expect we’ll be using these css shapes on live sites in the very near future, but I think they’re something to get excited about. I’m excited by the possibilities the css shapes module offers, especially when non-floated elements are later included into the mix.

I hope at some point we’ll have more control setting the background to sit behind the defined shape instead of the containing box. Assuming that happens, we’ll no longer be constrained to treat every element as a rectangular box.

Down the line this should open up many possibilities for more complex and richer compositions, which again is something that should excite you.

« »

Download a free sample from my book, Design Fundamentals.

8 comments

    • Thanks Alan. I just looked up clip-path and oddly enough I see it falls under masking, which is one of the topics I plan on covering in the next few weeks.

      I’ll give it a try and see what I can do with it.

    • Yeah, I’m looking forward to it as well. I think it creates a lot of new possibilities. I hadn’t realized Chrome isn’t going to support regions. I’ve seen some of the recent talk about regions, though I missed the part about Chrome. I’ve collected a few articles though. I thought I’d dig in and write another post on regions.

  1. Hi,
    I have tried to do it but I could get right effect with this css and html what you have displayed in your result.
    Where is CSS of “container” why does the css contain in the program? something is hidden there?
    Look forward to hearing your answer.
    Thanks@Amit

    • Hi Amit. What browsers were you testing with? Just a reminder that there’s limit support for CSS Shapes still. Only Chrome, Opera, and Safari support shapes at the moment.

      The css for the container was just to set a width and then center the container using margin: auto. I also added position: relative, though I don’t entirely remember why.

Leave a Reply

Your email address will not be published. Required fields are marked *