Gridded Headings

Published 11 months, 1 week ago

In my ongoing experiments with both a realignment of meyerweb’s design and CSS Grid, I came up with an interesting heading-and-subheading technique I’d like to share.  It allows two elements to be centered as a block, while letting them text-align with respect to each other, while still line-wrapping if necessary.

Here’s a little demobox.

These Are Grid Headings

A useful technique

Boxes and Alignment

It’s the new hotness

Cool

This is pretty darned easy to implement

Gridded Headings

Wednesday, 19 May 2017

Each heading-subheading pair is composed of two heading elements wrapped in another element.  The wrapping element is the grid container for the headings, each of which become grid items.  This is the markup I used:

<div>
    <h2>These Are Grid Headings</h2>
    <h3>A useful technique</h3>
</div>

If you resize your browser window, or select the “Narrow” option, you should see that the boxes surrounding the headings stays as wide as the wider of the two headings.  It “shrink-wraps” them, visually speaking.  In addition, those boxes stay centered within the grid container.

Furthermore, given the demo’s defaults, the two headings are left-aligned with respect to each other.  You can change this: for example, if you choose to “Center-align headings”, the h2s will center when they’re shorter than the subheadings (the h3s).  On the other hand, if you select “Right-align subheads”, then the subheads will right-align themselves with respect to the headings whenever the subhead is shorter in length.

That was actually a bit misleading: if the headings are centered, they’re centered whether or not they’re shorter than the subhead.  It’s just that, if they’re longer, you can’t see that they’re centered, because left-, center-, and right-aligning them has the same effect.  Ditto for right-aligning the subheads: if they’re longer, they sit in the same place regardless of their text alignment.

The alignments hold even when line-wrapping kicks in.  Try narrowing things down to the point that the text starts wrapping.  If you’re having trouble visualizing the two elements, turn on “Separate backgrounds” to given the heads and subheads visually distinct background colors.

So: a centered box as wide as the longest of the two elements, inside which they can align themselves with respect to each other.  Here’s the CSS that makes this possible:

display: grid;
grid-template-columns:
    minmax(1em,1fr)
    minmax(min-content,max-content)
    minmax(1em,1fr);

That’s pretty much it.  The first and third grid tracks are set to be a minimum of 1em, and a maximum of 1fr.  Given the second track (which I’ll get to in a moment), this means the two tracks will split any free space within the grid container, down to a minimum of 1em.  That’s how the centering of the box work; or, if you turn off “Boxes”, how the unbounded text sticks together in the center of the layout area.

That second track, minmax(min-content,max-content), is what makes all the unusual aspects of this possible.  What that says is: “make this grid track no narrower than the narrowest of the grid items in the track, and no wider than the widest grid item”.  In practice, it’ll most likely be as wide as its widest element.

But if I just said max-content (without having the minmax() and min-content parts) for that track width, the track would always be as wide as the widest element at its widest possible layout, which in this case means without line-wrapping the contents.  That would force particularly long headings to run outside of the track, and possibly out of the grid container altogether.  You can see this by enabling “Remove minmax” and narrowing things until text lines should wrap.

It’s the minmax(min-content,max-content) that avoids this fate, because that means that while the grid track (the column the head and subhead share) can’t get any wider than the widest element it contains, it’s allowed to get narrower.  Thus, if the grid container gets too narrow to fit all the grid items’ maximum widths, the contents of the grid items are able to line-wrap, thus avoiding overspill.  In fact, the grid items can keep getting more narrow until they reach min-content, which is to say, the narrowest the track can get without having content of any grid item stick out of the track.  Then it will stop shrinking.

And finally, if you want to see how the options you’ve selected will look in a Gridless browser, select “Remove grids” and see what happens.  Some combinations may not be palatable without Grid, but remember: you can always use @supports(display: grid) to quarantine any styles that are particularly egregious in older UAs.

So there you have it.  While I’m not certain the Grid drop quotes I wrote about last month will be used in the final version of my styles—I’m still looking to see if they’ll fit with more than 17 years of vaguely ad-hoc markup patterns—it’s pretty close to certain I will use these headings, minus the boxes.  I think they’re a neat effect for blog post titles and dates.

Addendum: As of May 2017, WebKit browsers (e.g. Safari) require vendor prefixes for the min-content and max-content keywords.


  1. Eric, these look amazing! Loving the grid more and more! Thanks for the heads up, maybe we should call the container element an “hgroup” or something?!? 🤔😏😎🤣

  2. Jon: I miss the HTML document outlining algorithm. I really do.

  3. RIP, <hgroup>. (I miss it too.)

  4. Slightly (ahem) OT — I was viewing this earlier on my iPad (portrait mode), the font-size of the page is a wee little bit too large (understatement for today: too large as in “yuuge”). Really. From the stylesheet: body { font-size: 2em; }. Just saying. That gave all kind of interesting effects on the demo… Try to view the page in Firefox responsive design view if you don’t have an iOS device at hand.

    (setting aside that Safari currently does not support minmax(min-content,max-content), you‘d need to prefix it)

  5. Whoops! Thanks for reporting that, Philippe. I cranked it down to a more reasonable level. Now I just have to remind Mobile Safari to act like a handheld device, not a tiny desktop computer.

  6. Note that the HTML spec recommends against using heading elements for subheadings. See http://w3c.github.io/html/common-idioms-without-dedicated-elements.html#subheadings-subtitles-alternative-titles-and-taglines

  7. I was very confused as to why it wasn’t working quite right in Safari until I read the aside in your comment, Philippe!

    Eric, perhaps you could clarify that in the post?

  8. Those examples given feel more like <h2>heading<sub>subheading</sub></h2> to me.

    I mean, they don’t feel like separate headings, it would not make sense to insert a paragraph or two between a headings and its subheading, so semantically, it feels like one heading element, not two.

  9. True, Šime. I see the pattern I used a lot in the field, so I was going off of a pattern I hoped would be familiar to readers, but I probably should have kept that in mind.

    Lee, sub is a subscript element, so it doesn’t feel right here either. I think the pattern Šime pointed to makes a bit more sense, although I dislike it as well. At least in cases where it’s title-date pattern, we could use time for the “subhead”!

  10. Good idea, Ben. Addendum appended. Thanks for the nudge!

  11. […] Gridded Headings – by Eric Meyer […]

  12. At some browser widths I see the boxes much wider than the headings, in both Chrome and Firefox. Not what is intended?

    Here is a screengrab of what I see: http://siberris.co.uk/content/gridded-headings

  13. Hey, Tim! That actually is what’s expected, given the combination of styles in play there. You’d see the same kind of sizing if the headings were normal flow instead of grid items, except without the shrink-to-fit or alignment behaviors at wider displays.

Leave a Comment

Management reserves the right to edit or remove any comment, especially when abusive or irrelevant to the topic at hand. HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <em> <i> <q cite=""> <s> <strong> <pre class=""> <kbd>


Comment Preview

If you're satisfied with what you've written, then go ahead...