Grid Lock

Last week I set myself a new productivity challenge. I don't want to dwell too much on that, but needless to say I think I've already abandoned it[1] 🤦 Y'see, I was meant to be spending this week:

[working on] a little JavaScript and CSS Grid experiment around a calendar...

I mean, I did technically do that, but then I got distracted by something ✨ sparkly ✨ and the original idea never really went anywhere. I might return to it in the future, but even if I did it wouldn't be for the Grid elements[2], which was the whole point originally. Anyway, instead I want to talk about the something sparkly, because that turned out to be both interesting and eye-opening (and actually about CSS Grid).

As tends to be the case, on Wednesday lunchtime I fired open The Old Reader for some daily RSS goodness, and picked a recent article from John Boardley on I Love Typography: The Prince & the fleur-de-lys. The article is interesting, but what really caught my eye was the page layout[3]. A cursory glance shows a central column of text, with two adjacent columns (or sidebars), one on each side: the left contains article details, such as the author and publish date; the right contains traditional "asides" such as image citations, additional text, footnotes etc. That alone is a very attractive and functional layout, but look a little closer and you realise there's actually a lot more flexibility going on. Quotations, for example, as well as some key images, are able to expand out further than the two sidebars, whilst still appearing constrained on desktop[4]. Image captions/citations can either be placed beneath the image, and therefore within the flow of the main article, or to one side. Indeed, those sidebars aren't rigid themselves, with one image and caption towards the end of the article partially overlapping the main article text, which neatly wraps around the offset content whilst still maintaining complete paragraphs:

Overlapping Columns on I Love Typography
Example of an aside in the right-hand sidebar overlapping the main article text on I Love Typography.

There's clearly a lot of interesting code going on here, so I jumped into the developer tools and began poking around. What I discovered is that the entire layout is achieved using floats, which slightly blew my mind. Since getting back into web development I've become so accustomed to Flexbox and CSS Grid that seeing complex floats again was a bit jarring. It also gave me an idea; a cunning plan, you could even say. Here was a prime layout for modernisation, a real test of my front-end chops! So I fired up a CodePen and began recreating a section of the page that contained a number of the more unusual elements. I didn't want to rip off the entire article (and gave clear attribution at the top of the experiment), but I also wanted to stay faithful, so I have literally lifted five paragraphs, a quote, and several images. Hopefully the original author doesn't mind[5]!

Drafting the Grid

Obviously, I can't emulate the styles exactly, as that would require access to bespoke web fonts, but I think I managed to get the main article body pretty close to a 1:1 replica. I also (even if I say so myself) nailed the blockquote, which I think is the biggest success of the little experiment. I never actually peaked at that area of the source, so I'm not sure how it's working on the live site, but it's definitely a perfect use of CSS Grid.

Attempt at Emulating Blockquote from I Love Typography
My attempt at emulating the full width blockquote from I Love Typography.
Original Blockquote from I Love Typography
For comparison, the original blockquote on I Love Typography. Apart from the web fonts (which are much nicer in the original), I think this was a pretty solid effort.

I first decided that my grid needed to have 5 columns: two outer columns that elements like quotations and large images could "overflow" into; two "sidebar" columns for the various asides in use; and a single, central main column, which houses the actual article. As I'm emulating a blog article, the whole experiment sits within an <article> element, which is set to display: grid. That five-column layout is then particularly easy, as are the small gutters present in the original design, by using:

article { 
 display: grid;
 grid-gap: 0 1rem;
 width: 100%;
 grid-template-columns: 10rem 18rem 28rem 18rem 10rem;
 grid-template-rows: auto;
 justify-content: center;
}

The specific column widths were chosen to emulate the original site, but if I was using this in an actual project I'd probably opt for a minmax to give it some flexibility.

With that in place, it was a question of forcing my HTML elements into the correct columns. Again, with Grid, that's not exactly tricky, particularly because my markup is fully semantic[6]. That means I can simply place all <p> elements into the third column; <aside>'s are slightly trickier, as they can either be in the left or right sidebars, so for those I created two helper/utility classes called .grid-right and .grid-left. I'm not completely sold on those names (I think it would be better to be more specific e.g. .article-sidebar-right), but for this experiment it'll do. Those helpers also handily allow me to easily distinguish between <img> elements that will appear within the main document flow and those that should become asides, thanks to class having higher specificity than just an element. Finally, as all quotations want to span all five columns, that becomes the easiest of the bunch by telling <blockquote> to span from grid-column: 1 / -1, effectively saying "from the start of the grid, to the end of the grid". Together that looks like:

p, img {
 grid-column: 3;
}

blockquote {
 grid-column: 1 / -1;
}

.grid-right {
 grid-column: 4;
}

.grid-left {
 grid-column: 2;
}

Chuck on some fancy background colours, fiddle with the type a bit, and that's pretty much core layout stuff done! Or... is it? That certainly ticks off the quotation styling, but it leaves us with some problems when it comes to the sidebars.

Grid Limits

The big one is that Grid works like a table, so each new row sits beneath the previous one. That's completely logical and I don't think it should work any other way, but it means that sidebar content always has to be smaller in height than the element in the middle column that it sits next to, otherwise your article ends up with a gap. There's currently no (practical[7]) way to get around this issue, as Grid is behaving as it should do, regardless of whether or not I want the output effect.

The second big issue is related to semantic markup and should be solved by Subgrid, once that achieves decent browser support. What I'm talking about is the images that have citations or captions in the sidebar. Semantically, these probably ought to be considered as <figure>'s with <figcaption>'s, which need to be nested, e.g.:

<figure>
 <img src="">
 <figcaption>Cited from here</figcaption>
</figure

Can you spot the issue? Because <figcaption> is nested within <figure>, you can't separate them within the Grid. In an ideal world, you'd be able to give <figure> a grid position of grid-column: 3 and <figcaption> a position of grid-column: 4, or use those helper classes we created to set it to .grid-right, but that doesn't do anything because the <figcaption> is out of scope for the Grid layout. From what I understand, Subgrid should help with this, as you might be able to pass that scope down to the <figcaption>; I'm not 100% sure about that, but I feel like it might be possible in the future. If I'm wrong then I have no idea how you'd ever be able to do something like this with Grid alone.

One possible fix is to set <figure> to position: relative and then absolutely position the <figcaption> to the relevant side. It has nothing to do with CSS Grid, but it should achieve a similar effect[8].

But even then, there's one layout option on I Love Typography which feels like it has to use floats: the "partial sidebar" shown above. Honestly, I think this is a perfect use of float and I'm not sure if there's any other way to achieve it. I briefly considered using CSS Shapes, but I don't think that would be of any benefit. It definitely wouldn't work with Grid, as the only way to overlap text from one grid cell to another is to use absolute positioning, but that would remove it from the document flow in the first place (so CSS Shapes can't calculate how to flow around it). Again, it feels like Grid maybe isn't the best solution after all.

Which, I have to admit, was my overall conclusion. Whilst there are a lot of really interesting experiments in converting old magazine and poster layouts to the web using Grid floating[9] around these days, in this instance I don't think Grid is good enough. I'll put my hands up here and point out that I'm very new to Grid! As such, it could very well be my understanding which is lacking, rather than a genuine limitation of Grid itself, but I have done a fair bit of Googling to come to that conclusion, so, y'know...

At any rate, simply failing at replicating this layout has taught me a huge amount about the underlying technology, so it was definitely worthwhile. I also remain incredibly excited and energised by what Grid does enable (even if this isn't that, if you see what I mean); in fact, twice in the latter half of this week I've reached for Grid (successfully!) to solve problems in live projects at work, neither of which I would have thought to use it for in the past. So I'm definitely chalking it up as a win! and felt like writing it up so that somebody else, including future me, could maybe gain some of that same insight in a little less time. 😉

PS: I might continue playing around with it, but if you'd like to try out my little demo you can view the CodePen here; feel free to fork it and mess around yourself (and let me know if you manage to make any of the above actually work!).

Footnotes