A Redesign With CSS Shapes

Here at An Event Apart we recently refreshed the design of our “Why Should You Attend?” page, which had retained an older version of our site design and needed to be brought into alignment with the rest of the site. Along the way, we decided to enhance the page with some cutting-edge design techniques: non-rectangular float shapes and feature queries.

To be clear, we didn’t set out to create a Cutting Edge Technical Example™; rather, our designer (Mike Pick of Monkey Do) gave us a design, and we realized that his vision happened to align nicely with new CSS features that are coming into mainstream support.  We were pleased enough with the results and the techniques that we decided to share them with the community.

Here are some excerpts from an earlier stage of the designs.  The end-stage designs weren’t created as comps, so I can’t show their final form, but these are pretty close.

Late-stage design comps showing “desktop” and “mobile” views

What interested me was the use of the circular images, which at one point we called “portholes” but which I came to think of as “bubbles.”  As I prepared to implement the design in code, I thought back to the talk Jen Simmons has been giving throughout the year at An Event Apart.  Specifically, I thought about CSS Shapes, and how I might be able to use them to let text flow along the circles’ edges—something like this.

Flowing around a circular shape

This layout technique used to be sort of possible by using crude float hacks like Ragged Float and Sliced Sandbags, but now we have float shapes!  We can define a circle, or even a polygon, that describes how text should flow past a floated element.

“Wait a minute,” you may be saying, “I haven’t heard about widespread support for Shapes!” Indeed, you have not. They’re currently supported only in the WebKit/Blink family—Chrome, Safari, and Opera. But that’s no problem: in other browsers, the text will flow past the boxy floats the same way it always has. The same way it does in the design comps, in fact.

The basic CSS looks something like this:

img.bubble.left {
    float: left; margin: 0 40px 0 0 ;
    shape-outside: circle(150px at 130px 130px);
    }
img.bubble.right {
    float: right; margin: 0 0 0 40px;
    shape-outside: circle(150px at 170px 130px);
    }

Each of those bubble images, by the way, is intrinsically 260px wide by 260px tall.  In wide views like desktops, they’re left to that size; at smaller widths, they’re scaled to 30% of the viewport’s width.

To understand the shape setup, look at the left-side bubbles.  They’re 260×260, with an extra 40 pixels of right margin.  That means the margin box (that is, the box described by the outer edge of the margins) is 300 pixels wide by 260 pixels tall, with the actual image filling the left side of that box.

This is why the circular shape is centered at the point 130px 130px—it’s the midpoint of the image in question.  So the circle is now centered on the image, and has a radius of 150px.  That means it extends 20 pixels beyond the visible outer edge of the circle, as shown here.

The 150px radius of the shape covers the entire visible part of the image, plus an extra 20px

In order to center the circles on the right-side bubbles, the center point has to be shifted to 170px 130px—traversing the 40-pixel left margin, and half the width of the image, to once again land on the center.  The result is illustrated here, with annotations to show how each of the circles’ centerpoints are placed.

Two of the circular shapes, as highlighted by Chrome’s Inspector and annotated in Keynote (!)

It’s worth examining that screenshot closely.  For each image, the light blue box shows the element itself—the img element.  The light orange is the basic margin area, 40 pixels wide in each case.  The purple circle shows the shape-outside circle.  Notice how the text flows into the orange area to come right up against the purple circle.  That’s the effect of shape-outside.  Areas of the margin outside that shape, and even areas of the element’s content outside the shape, are available for normal-flow content to flow into.

The other thing to notice is the purple circle extending outside the margin area.  This is misleading: any shape defined by shape-outside is clipped at the edge of the element’s margin box.  So if I were to increase the circle’s radius to, say, 400 pixels, it would cover half the page in Chrome’s inspector view, but the actual layout of text would be around the margin edges of the floated image—as if there were no shape at all.  I’d really like to see Chrome show this by fading the parts of the shape that extend past the margin box.  (Firefox and Edge should of course follow suit!)

At this point, things seem great; the text flows past circular float shapes in Chrome/Safari/Opera, and past the standard boxy margin boxes in Firefox/Edge/etc.  That’s fine as long as the page never gets so narrow as to let text wrap between bubbles—but, of course, it will, as we see in this screenshot.

The perils of floats on smaller displays

For the right-floating images, it’s not so bad—but for the left floaters, things aren’t as nice.  This particular situation is passably tolerable, but in a situation where just one or two words wrap under the bubble, it will look awful.

An obvious first step is to set some margins on the paragraphs so that they don’t wrap under the accompanying bubbles.  For example:

.complex-content div:nth-child(even):not(:last-child) p {
    margin-right: 20%;
}
.complex-content div:nth-child(odd):not(:last-child) p {
    margin-left: 20%;
}

The point here being, for all even-numbered child divs (that aren’t the last child) in a complex-content context, add a 20% right margin; for the odd-numbered divs, a similar left margin.

That’s pretty good in Chrome, with the circular float shapes, because the text wraps along the bubble and then pushes off at a sensible point.  But in Firefox, which still has the boxy floats, it creates a displeasing stairstep effect.

On the flip side, increasing the margin to the point that the text all lines up in Firefox (33% margins) would mean that the float shape in Chrome would be mostly pointless, since the text would never flow down along the bottom half of the circles.

This is where @supports came into play.  By using @supports to run a feature query, I could set the margins for all browsers to the 33% needed when shapes aren’t supported, and then reduce it for browsers that do understand shapes.  It goes something like this:

.complex-content div:nth-child(even):not(:last-child) p {
    margin-right: 33%;
}
.complex-content div:nth-child(odd):not(:last-child) p {
    margin-left: 33%;
}

@supports (shape-outside: circle()) {
    .complex-content div:nth-child(even):not(:last-child) p {
        margin-right: 20%;
    }
    .complex-content div:nth-child(odd):not(:last-child) p {
        margin-left: 20%;
    }
}

With that, everything is fine in the two worlds.  There are still a few things that could be tweaked, but overall, the effect is pleasing in browsers that support float chapes, and also those that don’t.  The two experiences are shown in the following videos.  (They don’t autoplay, so click at your leisure.)

Captured in Chrome; higher resolution available (3.3MB)
Captured in Firefox; higher resolution available (2.9MB)

Thanks to feature queries, as browsers like Firefox and MS Edge add support for float shapes, they’ll seamlessly get the experience that currently belongs only to Chrome and its bretheren.  There’s no browser detection to adjust later, no hacks to clear out.  There’s only silent progressive enhancement baked right into the CSS itself.  It’s pretty much “style and forget.”

While an arguably minor enhancement, I really enjoyed the process of working with shapes and making them progressively and responsively enhanced.  It’s a nice little illustration of how we can use advanced features of CSS right now, without the usual wait for widespread support.  This is a general pattern that will see a lot more use as we start to make use of shapes, flexbox, grid, and more cutting-edge layout tools, and I’m glad to be able to offer this case study.

Further reading

If you’d like to know more about float shapes and feature queries, I can do little better than to recommend the following articles.