Dev

Flexy Layouts

Tiny flexy helpers to handle all your layout needs.

I’ve been using flexbox on client work for over 2 years now. In that time, I’ve learned a great deal about the spec, where it shines, and perhaps more importantly, where it flounders.

For staters, it’s not the layout golden ticket heralded by so many before it dropped. But, if you’re aware of its limitations and proper use, flexbox can result in much cleaner, and far less, code.

Grids on the Parent

Most flexbox grid systems currently in the wild are essentially updated versions of the whole float-based 12 columns thing, with flex-basis replacing width. And that’s cool. We’ve adapted our own tried-and-true grid in a similar fashion.

However, in moving towards BEM syntax and more modular / component-based builds, our use of grid helper classes has significantly diminished. This especially rings true when dealing with CMS generated content with unknown child elements – a pattern common to all of our builds these days. Instead, we’ve been rocking a handy little flexbox mixin that’s applied directly to grid containers.

The Mixin


//----------------------------------------------  
//  flex-grid();
//  Creates grid blocks via flexbox

//  @param: $sm, $med, $lg, $xl - @media sizes
//  @param: $pad  - item padding  
//  @useage: @include g-blocks(1, 2, 3, 4, 0.5em);
//----------------------------------------------
@mixin flex-grid($sm:null, $med:null, $lg:null, $xl:null, $pad:0) {
  display: flex;
  flex-direction: row;
  flex-flow: wrap;
  margin-left: -$pad;
  margin-right: -$pad;
  list-style: none;

  & > * {
    padding: $pad;
    flex-basis: 100%/$sm;
    max-width: 100%/$sm;
    
    @media (min-width: $mq-med) {
      flex-basis: 100%/$med;
      max-width: 100%/$med;
    }

    @if $lg {
      @media (min-width: $mq-large) {
        flex-basis: 100%/$lg;
        max-width: 100%/$lg;
      }
    }

    @if $xl {
      @media (min-width: $mq-xlarge) {
        flex-basis: 100%/$xl;
        max-width: 100%/$xl;
      }
    }
  }
}

//----------------------------------  
//  Media Queries
//----------------------------------
$mq-small: 32em;
$mq-med: 54em;
$mq-large: 65em;
$mq-xlarge: 91em;

Usage

The mixin itself takes 5 arguments – The first 4 relate to the number of columns across 4 breakpoints (sm, med, lg, xl), and the last applies column padding. The arguments are optional, so you can add just what you need without generating any extra output. As you can see, we’re using the universal selector so you can apply the grid to any parent, without having to alter your column classes – ideal for BEM syntax.

For the following examples, lets say we have a parent class called .blocks, with childs named .blocks__item (though, the child name is irrelevant). Here are a few grid possibilities:

1 column at sm, 2 at med, 3 at lg, 4 at xl, with 0.5em of padding:

.blocks{
  @include g-blocks(1, 2, 3, 4, $pad:0.5em);
}

2 columns at sm, 3 at med, 4 at lg, with 0.5em of padding:


.blocks {
  @include g-blocks(2, 3, 4, $pad:0.5em);
}

1 column at small, 3 at medium, with 1em of padding:


.blocks {
  @include g-blocks(1, 3, $pad:1em);
}

You get the idea.

Flexy Columns Helpers

If you just need to build out some simple columns, instead of a repeating grid element, here are 2 little helper mixins that can satisfy all your layout needs.

The following flex-row mixin creates the wrapper, applying flex with some simple options for positioning and alignment.


//----------------------------------------------  
//  Flex Row
//  A helper to create flex rows
//
//  @param align - vert alignment
//  @param $justify - horx positioning
//  @param $wrap - wrap / no-wrap
//  @mobile $mobile (boolean) - start row on mobile 
//----------------------------------------------
@mixin flex-row($align: null, $justify:null, $wrap: wrap, $mobile:false, $direction:row){
  direction: $direction;
  @if $align {
    align-items: $align;
  }
  @if $justify{
    justify-content: $justify;
  }
  @if $mobile == true {
    display: flex;
    flex-wrap: wrap;

  } @else {

    @media (min-width: $mq-med){
      display: flex;
      flex-wrap: $wrap;
    }
  }
}

And, this flex-col() mixin builds out the columns within the flex-row wrapper, with options for size/width. We’re adding more than just flex-basis to safeguard against browser inconsistencies (see below).


//----------------------------------------------  
//  Flex Column
//  A helper to output cross browser requirements for 
//  columns inside a flexbox parent. flex-basis isn't
//  enough in all cases.
//
//  @param $width (size), $mobile (boolean)
//----------------------------------------------
@mixin flex-col($width, $mobile:false){
  @if $mobile == true {
    flex-basis: $width;
    width: $width;
    max-width: $width;

  } @else {

    @media (min-width: $mq-med){
      flex-basis: $width;
      width: $width;
      max-width: $width;
    }
  }
}
Usage – The markup structure

<section class="mast">
  <!-- Container class -->
  <div class="grid">
    <!-- Our Flex Row -->
    <div class="mast__grid">
      <!-- Flex Col -->
      <div class="mast__col">
      <!-- Johnny Content -->
      </div>
      <!-- Flex Col -->
      <div class="mast__col">
      <!-- Johnny Content -->
      </div>
    </div>
  </div>
</section>
Usage – the CSS/SCSS

.mast{
  &_grid{
    @include flex-row($align:center);
  }

  &__col{
    @include flex-col(50%);
  }
}

Here’s a little demo of the mixin in action, and you can also snag the code on Github

Flexbox Caveats

While flexbox is well supported now, there are plenty of browser related issues that you’ll encounter. Here are a few that we’ve run into:

  • Firefox – no percentage paddings
    While all other browsers respect percentage paddings/margins in a flex layout, Firefox won’t play ball. Admittedly, this interpretation of the spec is not incorrect, but it still sucks and Mozilla’s Daniel Holbert has been a tad indignant on the matter, after enjoying an onslaught of bug reports. Amusingly, homie went so far as to file a Chrome bug report (do you playa).

    I’d argue that the spec should be revised regarding this matter, and luckily, the W3C working group is currently taking it under consideration.

    Sadly, no percentages also means no instrinsic-ratio, padding-bottom moves, unless you nest. Lame.

  • More Firefox woes

    For some reason, Firefox needs a min-height and min-width applied to flex elements. We’ve solved this with the following:

    
    // Firefox flexbox fix
    * {
      min-width: 0;
      min-height: 0;
    }
  • IE Needs a backup for Flex-basis percentage sizing, namely max-width.
    On IE, flex-basis often isn’t enough. So, add an additional max-width of the same percentage.

More on Flex

For more on flexbox bugs and fixes, check out Philip Walton’s Flexbugs community collection repo.

Learn more about the spec here.

For a complete guide to Flexbox, check this CSS Tricks article.

Demo & Downloads

Demo

Github

Read Next

The New INRIX

Read Story