A Brief Foray Into CSS Shapes

I often use my website as a playground for new technology, so thought I’d try making use of CSS Shapes, after getting suitably inspired by this example.
First off, as of August 2014, support for CSS Shapes Module Level 1 is magnificently poor (with only dev channel versions of both Chrome (unprefixed) and Safari (prefixed with -webkit-
) harbouring working versions), so I had to implement it in a way that would only progressively enhance the current layout, as opposed to making changes that would destroy the vast majority of users’ experiences.
Why CSS Shapes?
The web has always played second fiddle to print when it comes to layout. Desktop Publishing (DTP) programs have long had the ability to wrap text around shapes and images, whereas web designers have been able to do little more than float blocks of text to the left or right of the screen. Things are set to change though, as the W3C official spec states:
Shapes define arbitrary geometries that can be used as CSS values. This specification defines properties to control the geometry of an element’s float area. The shape-outside property uses shape values to define the float area for a float.
This adds a whole wealth of exciting opportunities for web designers, such as this one by Razvan Caliman.
CSS Shapes Implementation
The basic syntax takes the following form:
.element {
[shape-property]: [shape function]([shape parameters]) [box value];
}
Shape Property can take on the values of shape-outside
or shape-inside
. The former wraps the content outside (around) a shape, whereas the latter wraps the content inside a shape. Nice and simple.
Shape Functions and their relative arguments are as follows:
Shape Function | Shape Arguments | Working Code | Live Example |
---|---|---|---|
circle() | [<shape radius>] at [<position>] | circle(200px at 50% 50%) | CodePen Link |
ellipse() | [<shape radius x> <shape radius y>] at [<position>] | ellipse(250px 125px at 50% 50%) | CodePen Link |
inset() | [<top offset> <right offset> <bottom offset> <left offset>] | inset(20% 40px 30% 50px) | CodePen Link |
polygon() | [nonzero/evenodd], [<x1> <y1>], [<x2> <y2>], [<x3> <y3>] etc. | polygon(0% 0%, 100% 0%, 100% 100%) | CodePen Link |
Note that for polygon()
to work, at least three sets of coordinates must be declared. Three will generate a triangle, four will generate a quadrilateral etc.
Box Value can take the value of margin-box
, border-box
, padding-box
, or content-box
. This closely follows the arguments associated with the box-sizing
CSS property, with the addition of margin-box
.
What I Did
As a little bit off visual niceness, I simply made the body text of certain pages (such as the home page) wrap around the rotating logo at the top of each page. As CSS Shapes requires floated elements to provide the ‘shape’, I had to implement a bit of a hack, due to the logo existing as a pseudo element (or two separate pseudo elements, to be precise). For this reason, I had to add a blank div
, to act as a mask over the logo (not ideal I know, but hey – it’s only a div
!).
The result looked something a bit like this:

The HTML markup looked like this:
<section class="section-standard">
<h1>Page Title</h1>
<div class="shape-logo-mask"></div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed iaculis odio risus, ut condimentum neque pellentesque vitae.</p>
</section>
And the CSS:
@supports ( -webkit-shape-outside: circle(300px at 50% 50%) border-box ) or ( shape-outside: circle(300px at 50% 50%) border-box ) {
.section-standard:first-of-type p {
word-break: break-word;
-webkit-hyphens: auto; /* Safari 5.1 & iOS Safari 4.2 */
-moz-hyphens: auto; /* Firefox 6 */
-ms-hyphens: auto; /* IE 10 */
hyphens: auto;
}
.shape-logo-mask {
float: right;
width: 600px;
height: 600px;
margin: -298px -210px 20px 20px;
-webkit-shape-outside: circle(300px at 50% 50%) border-box;
shape-outside: circle(300px at 50% 50%) border-box;
-webkit-shape-margin: 20px;
shape-margin: 20px;
}
}
It was necessary to place all of the new CSS statements within a @supports
rule, as I only wanted .shape-logo-mask
to take on explicit dimensions and positioning if the browser supported CSS Shapes. This way, if CSS Shapes isn’t supported, the div
gets rendered as a 0px by 0px box, and the layout remains unaffected.
So let’s deal with the basics first. .shape-logo-mask
is given dimensions of 600px x 600px, and floated right. It’s also given a couple of negative margins, so that it sits directly over the logo. At this point, the paragraph text steers clear of the logo as you’d expect, but doesn’t wrap around its curve as intended.

As for the new code, shape-outside: circle(300px at 50% 50%) border-box
defines a circle with a 300px radius from the centre of .shape-logo-mask
, lining up perfectly with the logo, creating the following:

Note that I’m using Chrome 39 (Canary at the time of writing) to create each of the screenshots. Chrome 37 does successfully draw the box when inspected with Dev Tools, but didn’t seem to render the logo underneath, and also didn’t update the shape’s position on page scroll.
Current Drawbacks
Apart from the obvious lack of support, you’ll notice that on my site, the text doesn’t always ‘hug’ the shape as intended (if viewing in Chrome 37+). This is partly down to the size of the text (I know 24px isn’t for everyone, but I’m kinda enjoying it at the mo), and partly down to the lack of hyphenation support in said browser (which would certainly help squeeze things up closer). Strangely, Chrome and Android browser support -webkit-hyphens: none;
, but not -webkit-hyphens: auto;
, meaning that for now, Safari 8 and iOS Safari 8 are the only browsers to take everything into consideration. For a bit of future-proofing however, I have included the suggested hyphenation stack from CSS Tricks.
In Conclusion
Would I use CSS Shapes on a client’s production site? Not yet. Will I continue to use it on my own site? Probably, although whether it remains where it currently is, only time will tell.