Making our Flexbox Grid Responsive with Less

Sara Vieira

If you have been following along with this Flexbox grid series you know that in the previous article we created a simple flexbox grid that had columns and offsets, but it wasn't responsive yet and we can't have that right?

Let's start making this grid responsible so that you can use it in any project you may have.

The Breakpoints

In this grid I decided to have three breakpoints, s, m and l , anything above l uses the primary columns and if you remember those were the column classes that had no prefix, like: col-12. First thing we need to do is set this in our _vars.less so that anyone can change this to fit their project:

// _vars.less

@s:~"only screen and (max-width: 480px)"; // Small Phones
@m:~"only screen and (max-width: 768px)"; // Normal Phones
@l:~"only screen and (max-width: 1024px)"; // Tablets

Basically what you see is all the breakpoints I think you could ever need for mobile but if you believe more are needed, please add your own and name it something you like. You will see how to integrate these breakpoints in a little while.

Creating the loops

We already created a loop for our non-responsive breakpoints, and it looked like this:

//_loops.less

// Loop for normal cols
.generateCols(@counter) when (@counter > 0) {
  @width: (@counter / @cols ) * 100;
  .col-@{counter} {
    flex-basis: ~"@{width}%";
    max-width: ~"@{width}%";
  }

  .col-offset-@{counter} {
    margin-left: ~"@{width}%";
  }
  .generateCols(@counter - 1));
}

If you look at the code, you see that in this case the loop takes one argument and that is the column number. That's great for grids that are not responsive, but when you want to create breakpoints you also need to need it to generate the classes with the current breakpoint name, so we will need to create a new loop in our _loops.less and this one will create our responsive columns:

_loops.less

// Create the responsive loops that also takes the media as an argument
// this media is our breakpoints
.generateResponsiveCols(@counter, @media) when (@counter > 0) {
     // In here we define the width 
    // and this will be the number of the column we are in divided by the number of columns we have.
    // Imagine this is column 6 and this will give us 0.5 and if multiply it by 100 we will get 50%
    @width: (@counter / @cols ) * 100;

    // we used to only have .col-@{counter} but now that we added the media param
    // we insert it here so that it creates classses like .col-s-10 and we can use this in our grid
    .col-@{media}-@{counter} {
        flex-basis: ~"@{width}%";
        max-width: ~"@{width}%";
    }

    // Create our resposnive offset classes
    .col-offset-@{media}-@{counter} {
        margin-left: ~"@{width}%";
    }
    // Decrease the counter by one so we don't have an infinite loop
    // and also pass it the media so that it generates the next loop
    .generateResponsiveCols((@counter - 1), @media);
}

So we have our loops, and they will generate all our desired classes, but we still need to call these loops for them to create the classes we need so now we move to our _grid.less and create all the media queries we need, and inside each of them we call our generateResponsiveCols mixin and pass it the number of columns and our current breakpoint.

 _grid.less

  .row,
  .column {
    ...

    @media @l {
        // Call our large columns
        .generateResponsiveCols(@cols, l);
    }

    @media @m {
        // Call our medium columns
        .generateResponsiveCols(@cols, m);
    }

    @media @s {
        // Call our small columns
        .generateResponsiveCols(@cols, s);
     }
}

Now if you run gulp less in your console and open up our HTML you should be able to see our responsive columns at work. If you resize, you will find that they behave according to the breakpoint you are currently viewing on the browser.

Phone View

Phone View

iPad portrait view

iPad portrait view

iPad landscape view

iPad landscape view

So we got our responsive classes working great, but we are still missing one thing, a crucial part in any responsive grid is the ability to hide columns by the size of the screen, and as you can see by our phone view this is not happening yet, and it's time to add it. For simplicity I will call these classes col-s-hidden, .col-m-hidden, col-l-hidden, .col-hidden to cover all our column names and breakpoints. Adding these classes should be relatively easy since all we need to do is hide the desired column in the correct breakpoint. But something like this is better explained through code:

    // grid.less

    @media @l {
        .generateResponsiveCols(@cols, l);

        // hide any element that has the class col-l-hidden
        .col-l-hidden {
            display: none;
        }

        // show all the other hidden elements that were meant for other breakpoints
        .col-s-hidden,
        .col-m-hidden,
        .col-hidden {
            display: block;
        }
    }

All we did here was hide the column that matched the breakpoint and show all the other columns since those that did not match the breakpoint. Now that we saw how to add these classes let's do the same for all the other breakpoints:

// grid.less

  .row,
  .column {
     ....

    // Aply hidden classes to the "primary" columns
    .col-s-hidden,
    .col-m-hidden,
    .col-l-hidden {
        display: block;
    }

    .col-hidden {
        display: none;
    }

    // add hidden classes to our l breakpoint
    @media @l {
        .generateResponsiveCols(@cols, l);

        .col-s-hidden,
        .col-m-hidden,
        .col-hidden {
            display: block;
        }

        .col-l-hidden {
            display: none;
        }
    }

    // add hidden classes to our m breakpoint
    @media @m {
        .generateResponsiveCols(@cols, m);

        .col-s-hidden,
        .col-l-hidden,
        .col-hidden {
            display: block;
        }

        .col-m-hidden {
            display: none;
        }
    }

    // add hidden classes to our s breakpoint
    @media @s {
        .generateResponsiveCols(@cols, s);

        .col-m-hidden,
        .col-l-hidden,
        .col-hidden {
            display: block;
        }

        .col-s-hidden {
            display: none;
        }
    }
}

Now if you reload our index.html and use a small screen size you will see something like:

That's it for the responsive part of our grid, as you could see since we already had the foundation from our previous loops doing this part was a breeze.

Adding Helper Classes

Something that I appreciate to see in any grid or CSS framework is helper classes. What I mean by helper classes is anything that helps me align the elements according to how I want to see them in that container. With flex, we can do this easily using align-items and justify-content so let's add some horizontal alignment to our grid:

// grid.less

.container {
....
    .justify-center {
        justify-content: center;
    }

    .justify-end {
        justify-content: flex-end;
    }

    .justify-start {
        justify-content: flex-start;
    }

    .justify-around {
        justify-content: space-around;
    }

    .justify-between {
        justify-content: space-between;
    }
}

if you try to add one of these classes to our columns, you will see that it does indeed work, but the problem is that if you try to add this to the ul for example, it won't do anything because the ul is not a flex container. We need to make sure that we always set elements that have a class that includes justify- to display: flex and to do something like that we add this before defining our justify classes:

// grid.less

[class*="justify-"] {
    display: flex;
}

And now we have fully working justify classes for all our horizontal alignment needs. You may be wondering where our vertical alignment classes are seeing that those are the tricky ones to do without flex, well to have our vertical we need to add this:

// grid.less

.container {
....
    [class*="items-"] {
        display: flex;
    }

    .items-center {
        align-items: center;
    }

    .items-start {
        align-items: flex-start;
    }

    .items-end {
        align-items: flex-end;
    }

    .items-stretch {
        align-items: stretch;
    }
}

And voilรก we got some pretty good helper classes to add to our grid and help us align all our elements. If there are some other classes, you feel like you need to improve your grid like margin and padding classes feel free to add them in this file, for me, these are the crucial ones to have on any grid.

Conclusion

As you can see creating a fully fledged grid using Less and flexbox is not as daunting of a task as you may have thought and that's because like in any programming task all you need to do is divide a large project into smaller less daunting tasks and start coding away.

I hope these tutorials helped you get a better grasp of Less loops and also made you have some love for it if you didn't already.

I will be releasing this as an open source grid for everyone to use shortly but in the meantime, you can see it on Github and let me know your feedback and of course hack my repository away.

Sara Vieira

5 posts

Sara Vieira is a Front-End Developer for Mindera in Portugal with a passion for everything front end related. She is also a drummer and a big time TV Show addict.