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
Table of Contents
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
iPad portrait 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.
Like this article? Follow @NikkitaFTW on Twitter