Playing With Flexbox and Quantity Queries

by {"name"=>"Aaron Gustafson", "twitter"=>"AaronGustafson", "googleplus"=>"AaronGustafson"} on 26 March 2015

Ever since reading Haydon Pickering’s piece on quantity queries, I’ve been musing over the possibilities for layout. I decided I to play around with them a bit on this site as it’s been a while since I’ve tweaked the design. Being that I wanted to experiment, I thought this would be a fun time to tuck into Flexbox a bit more as well.

Here’s a brief overview of the project:

The Candidate: My speaking engagements page.
The Challenge: The “Future” list will grow and shrink as I book things, so I never know how many will be there. The “Past” list will also grow, but I am less interested in getting crazy with that.
The Idea: A grid layout that flexes to visually highlight 1-2 upcoming future events and allows the others to flow in at the default grid size. It should be set up to handle everything from a single future event to a dozen or more.

My sketch of the idea.

The markup pattern was pretty simple. It’s just a list of events:

With that in place, I got to work.

Single File

To set the stage, I started with some basic Flexbox syntax1 by handling the container and the basic full-width small screen view:

You may be wondering where all of the experimental style rules are. I use Autoprefixer to handle the experimental property inclusion/trans-compilation so I can keep my CSS clean and standards-based.

This simple CSS gives you exactly what you’d expect: a vertical list of events, separated by 20px worth of space.

Two by Two

Next up, I tackled the first breakpoint at 28.75em:

In this pass, I set up the event blocks to fill 50% of the parent container (well, 50% minus the 1.25rem gutter between them, using calc()).2 In order to make the children wrap to form rows, I set flex-wrap: wrap on the list (.listing--events). Then, to make the children all equal heights across each row, I set align-items: stretch. The gutter space was achieved via left margins on all events save the row starters (.event:nth-child(odd)).

It’s worth noting that in the full page I have two sets of event listings: one past and one future. The “event” class is used in all instances. The modified “future” class is added to events that have not happened yet.

Then I used a quantity query to select the first future event when there is more than one in the list (line 38) and set it span 100% of the parent width. To keep the gutters accurate, I also swapped where the margins were applied, adding the margin back to .event--future:nth-child(odd) and removing it from .event--future:nth-child(even).

Three’s a Crowd

Finally, I could tackle the third and most complicated layout. Things seemed to get a little wide around 690px, so I set the breakpoint to 43.125em.

In this final pass, I used a slightly more complicated calculation to set the width of each child to 1/3 of the parent minus the gutters between them (100% / 3 - 0.875rem).

If you’re paying close attention, you might wonder why the gutter being used in the calculation is 0.875rem rather than the full 1.25rem. Well, the reason is (as best I can surmise) rounding. In order to get the flex width to fill the parent without causing a wrap, 14px (0.875rem) seemed to be the magic number.

It’s worth noting that if I allowed the event to grow (using flex-grow: 1 or its equivalent in the shorthand), the column would fill in perfectly, but the last row would always be filled completely too. You could end up with two events in the last row being 50% wide each or a single event being 100% wide, which I didn’t want. I wanted them all to be equal width with the exception of the first 2. Setting flex as I did allowed that to happen.

I went ahead and reset the standard margins for events as well (on both .event:nth-child(even) and .event:nth-child(odd)). And then I turned off the margins on the first of every group of three events using .event:nth-child(3n+1).

With that in place, I went to work on the future events, resetting the margins there as well. Then I used a quantity query (lines 70-71) to select the first two members when the list is more than 2 and set them to be 50% of the parent width minus the gutter.

To handle the margins in the quantity query instance, I added all the margins back (line 64) and then removed the left margins from the new row starters (line 77).

Ta-da!

And there you have it. In about 80 lines of very generously spaced and commented CSS, we’ve got a flexible grid-based Flexbox layout with visual enhancements injected via quantity queries. I’m sure I’ll continue to tinker, but I’m pretty happy with the results so far.

You can view the final page of course (or watch a video of the interaction), but I also created a distilled demo on Codepen for you to play with.

  1. If you aren’t familiar with Flexbox, CSS Tricks has a great cheatsheet

  2. Interestingly, the support matrices for calc() and Flexbox are pretty well aligned.