Simple SASS mixins for generating grids similar to bootstrap

February 3, 2018

I was recently faced with a problem for a small campaign site, where the site columns were going from 1 column at its smallest up to 5 columns at its largest.

Normally this isn’t a problem when you’re running with a 12 column grid and bootstrap, up until you reach 5 columns.

The way bootstrap’s grid is setup is that you specify how many columns you want an elements width to be, i.e. the classes col-xs-12 col-md-6 would have the element stretch 12 out of 12 columns at the xs size, and when the browser width reaches md, the element would stretch 6 out of 12 columns.

So that’s all fine and dandy.

Items per rowCalculationClass name
112/1 = 1col-*-12
212/2 = 6col-*-6
312/3 = 4col-*-4
412/4 = 3col-*-3
512/5 = 2.4col-*-2.4(?)

As you can see, a 12 column grid is not divisible by 5. 15 is, but that’s not divisible by 2 or 4.

The smallest number I can find that is evenly divisible by 1,2,3,4 and 5, is 60.

So I could run with a grid with 60 columns, but I don’t really like the idea of that many columns (even though they are only “virtual”). The other problem is that bootstrap only has four actual breakpoints; xs, sm, md, lg. And I need five.

So since this is a fairly small project, I decided to just roll my own grid, starting off by creating a grid generator in SASS

/*
 * Generates classes for a grid of columns, prefixed by size.
 * The result will be .col-[size]-[col]-[total-columns] E.g. .col-xs-6-12
 *
 * @param {string}	$size			The name of the size target (e.g. xs, sm, md, lg, xl, etc.)
 * @param {int}		$grid-columns	Amount of columns
 */
@mixin grid-generator($size, $grid-columns) {
	@for $i from 1 through $grid-columns {
		.col-#{$size}-#{$i}-#{$grid-columns} {
			width: percentage($i / $grid-columns);
			float: left;
		}
	}
}

I also need the grid to adjust to different types of screens, similar to bootstrap, I generally try to work from a mobile first perspective, so I have a mixin called respond-from, which you can use to add / modify css rules from a specific width and upward.

/*
 * A mixin targeting a specific device width and larger.
 * These are the available targets: 'xs', 'sm', 'md', 'lg', 'xl'
 *
 * @param {string} $media The target media
 */
@mixin respond-from($media) {
	@if $media == xs {
		@media (min-width: 0px)  { @content; }
	} @else if $media == sm {
		@media (min-width: 768px) { @content; }
	} @else if $media == md {
		@media (min-width: 1200) { @content; }
	} @else if $media == lg {
		@media (min-width: 1440) { @content; }
	} @else if $media == xl {
		@media (min-width: 1800) { @content; }
	}
}

And now, for the finale, to generate the grid, you only need to run this configuration to render the grid.

@include grid-generator(xs, 12);

@include respond-from(sm) {
	@include grid-generator(sm, 12);
}

@include respond-from(md) {
	@include grid-generator(md, 12);
}

@include respond-from(lg) {
	@include grid-generator(lg, 12);
}

@include respond-from(xl) {
	@include grid-generator(xl, 10);
	@include grid-generator(xl, 12);
}

And to actually have an element span the way we want the classes would be:
col-xs-12-12 col-sm-6-12 col-md-4-12 col-lg-3-12 col-xl-2-10

In my case I needed the grid to always have the width of the screen, but your use-case might differ, if that is so, you’ll also need to specify a container with the specific width’s that you need.

Tags