Editorial Layouts, Floats, and CSS Grid
CSS Grid is in many ways a dream come true, but there’s at least one basic thing it can’t do.
I’ve been getting my feet wet with CSS Grid this year. The new possibilities it introduces for page layout on the web are exciting, but before venturing too far into those waters, I wanted to see how it handles the kind of layouts I’m already designing. Most of the work I do on the web—at ProPublica and here on my site—is editorial design, so I was keen to learn how Grid accommodates the conventions of the form.
One of those conventions is the interspersion of photographs, illustrations, figures, and asides throughout the text of an article. A typical template is based on a columnar grid, which establishes the text area and various size and position options for supporting material. Take this simple example of a five-column article layout, with the main text flowing around a two-column image:
Here’s what the basic markup looks like:
<main>
<article>
<img src="photo.jpg">
<p>Lorem ipsum…</p>
</article>
</main>
I’ve written about this in detail previously, but in short, aligning that image to the grid in a layout like this has traditionally been accomplished using floats and percentage widths:
img {
display: block;
float: left;
margin-bottom: 8.856682769726248%;
margin-right: 8.856682769726248%;
width: 34.782608695652174%;
}
The beauty of CSS Grid is that, among other things, it makes grid alignment less abstract and more intuitive. Fewer declarations of arcane numbers with sprawling decimal places and more saying exactly what you mean. Here’s a first stab at modifying the CSS to achieve an identical result using CSS Grid:
article {
display: grid;
grid-gap: 8.856682769726248%;
grid-template-columns: repeat( 5, 1fr );
}
img {
display: block;
float: left;
grid-column: 1 / span 2;
width: 100%;
}
p {
grid-column: 1 / span 5;
}
In the above code, I’ve established a five-column grid context for the article
element and specified two-column and five-column spans for, respectively, the img
and p
elements. This is way less of a headache than calculating unwieldy percentages, which is great. But note that, perplexingly, grid-gap
won’t accept fr
units, so if we want the entirety of our grid to have flexible proportions, we’re still not completely rid of percentages. The first sign of trouble, and unfortunately not the last: As you can see in the result below, objects within a grid context (known as grid items) cannot float.
There are good reasons for this. Each grid item is meant to occupy its own two-dimensional grid area, and the float concept isn’t really compatible with that. But where does that leave those of us who want to wrap text around other objects while still keeping everything aligned to the grid? Alas, unless I’m missing something, it looks something like this:
main {
display: grid;
grid-gap: 8.856682769726248%;
grid-template-columns: repeat( 5, 1fr );
}
article {
grid-column: 1 / span 5;
}
img {
display: block;
float: left;
margin-bottom: 8.856682769726248%;
margin-right: 8.856682769726248%;
width: 34.782608695652174%;
}
This code establishes a grid context for main
so that other things on the page can make use of CSS Grid, but as far as our article layout CSS is concerned, we’re pretty much back where we started.
A Grid/float hybrid
Okay, so we need to use a hybrid of new and old methods. We’ve achieved the desired result and it’s not like Grid is actually making anything worse, right? Well, things can get pretty complicated pretty quickly when we try to take advantage of some of the new opportunities available in Grid.
Let’s start with something simple. The new fr
unit makes it easier to mix fixed- and fluid-width grid measurements, which means we no longer need to fear making our gutters relative to the text size rather than the container width. If I change the grid-gap
from that obnoxious 8.856682769726248%
to a more manageable 2em
, our grid is more sophisticated, but that increases the complexity of faking it in our article layout’s non-Grid context. Take a look at the calc
craziness now needed to get our img
to align to the grid:
main {
display: grid;
grid-gap: 2em;
grid-template-columns: repeat( 5, 1fr );
}
article {
grid-column: 1 / span 5;
}
img {
display: block;
float: left;
margin-bottom: 2em;
margin-right: 2em;
width: calc( 2 * ((100% - 8em) / 5) + 2em );
}
Let’s go a couple of steps further and throw nonstandard column widths into the mix. Rather than having five uniform 1fr
columns, let’s give them this admittedly ludicrous collection of values: 50px
, 3fr
, 7em
, 2fr
, 1fr
.
As you can probably guess, our img
’s calc
math is growing ever more gymnastic:
main {
display: grid;
grid-gap: 2em;
grid-template-columns: 50px 3fr 7em 2fr 1fr;
}
article {
grid-column: 1 / span 5;
}
img {
display: block;
float: left;
margin-bottom: 2em;
margin-right: 2em;
width: calc( 3 * ((100% - 50px - 15em) / 6) + 50px + 2em );
}
Now what?
As I said at the start, I’m really excited about all the new possibilities CSS Grid introduces, and I can’t wait to see how it empowers designers’ imaginations, my own included. But the new doesn’t need to come at the expense of the old, and I’m surprised and disappointed that Grid either didn’t anticipate this common use case or chose to exclude it.
The Grid spec continues to evolve, and hopefully it will make some room for floats (or an equivalent effect) in the future. Until then—again, unless I’m missing something—it looks like these types of editorial layouts will either need to get used to jumping through hoops or skip the CSS Grid party entirely.
Update, 9 Nov 2018: The amazing Rachel Andrew wastes no time! See her response about how CSS Exclusions—which are more capable than floats—could be the solution to this conundrum if they can get broader browser support. Today begins my crusade for CSS Exclusions! Follow this GitHub issue to keep track of the CSS Working Group’s progress.