Building a mobile-first grid with SCSS
Today we are going to explore how we can create a responsive grid framework with SCSS in ~20 lines of code that can be minified to 2kb.
The HTML
Let's start with what we want our HTML to look like. I believe in being as minimal as possible while remaining descriptive:
<div class="grid">
<div class="col s12 m6 l8">1</div>
<div class="col s12 m6 l4">2</div>
</div>
The above markup is an example of a grid with two columns that both show 100% (across all 12 columns) on small devices, 50/50 columns on medium devices and 8/4 on large devices. We can actually omit the s12 as columns will always default to 100%.
The SCSS
As defined above, we are using a 12 column grid system so the first thing we are going to do is create some variables to store our grid configuration:
// The number of columns the grid can have
$grid-items: 12;
// The responsive breakpoints for columns
$breakpoints: (s: 320px, m: 641px, l: 1025px);
Now, if you've been stuck in CSS and are new to the SCSS game you may be saying: 'Wait... Variables? What could that be for?'. Well, let me introduce you to dynamic class creation :D
SCSS give us the ability to loop from one number to another:
@for $i from 1 through $grid-items {
.col#{$i} {
flex: 0 0 percentage($i / $grid-items);
}
}
This will generate the css:
.col1 {
flex: 0 0 8.33333%;
}
.col2 {
flex: 0 0 16.66667%;
}
... etc ...
That's good and all, but it's not responsive :( Let's create one more variable below $grid-items that will define our responsive breakpoints:
// Loop through each breakpoint
@each $key,
$value in $breakpoints {
// Create the responsive media query
@media (min-width: $value) {
// Loop number of items in grid
@for $i from 1 through $grid-items {
// Create a responsive class for each breakpoint and column size
.col.#{$key}#{$i} {
flex: 0 0 percentage($i / $grid-items);
}
}
}
}
Now we can introduce the base grid and col classes to finish up our grid implementation:
// The number of columns the grid can have
$grid-items: 12;
// The responsive breakpoints for columns
$breakpoints: (s: 320px, m: 641px, l: 1025px);
// The grid class
.grid {
display: flex;
flex-flow: row wrap;
// Base column
.col {
flex: 0 1 100%;
}
// Responsive column classes
@each $key,
$value in $breakpoints {
@media (min-width: $value) {
@for $i from 1 through $grid-items {
.col.#{$key}#{$i} {
flex: 0 0 percentage($i / $grid-items);
}
}
}
}
}
Bonus
One last thing I like to do is to define classes to determine at what screen size to show an item:
@each $key,
$value in $breakpoints {
.show-#{$key} {
display: none;
@media (min-width: $value) {
display: unset;
}
}
}
These classes can be used like so to go from a single column on mobile to two columns on anything large:
<div class="grid"
<div class="col m6">1</div>
<div class="col m6 show-m">2</div>
</div>
I hope this can help you on your responsive web adventures.