During the recent refactoring of the Forward Technology site we decided to attempt to make it responsive to cater for the ever increasing variety of devices available, and seeing as we already used Sass we thought we’d put it to the test.
Traditionally, CSS grid systems implement useful but not necessarily semantic class names, such as “grid-8” or “grid-6 alpha”, that set the proportion of the total layout width each element should have, taking into account the gutter as well. For example, in a 12-column system, “grid-6” would effectively be 50%. The corresponding classes in the stylesheet specify the actual width for each class. In responsive grid systems, this is coupled with media queries to set a width for each different resolution, such as those shown in the Skeleton framework. The below table shows a sample of columns width (including a 10px gutter either side) in a 12-grid system at different resolutions.
| 1200px+ | 1200 - 960px | 959 - 769px | > 768px and mobile |
_______|__________|________________|_______________|____________________|
12 col| 1200px | 960px | 768px | 100% or auto |
-------|----------|----------------|---------------|--------------------|
1 col | 100px | 80px | 64px | 100% or auto |
-------|----------|----------------|---------------|--------------------|
4 col | 400px | 320px | 256px | 100% or auto |
-------|----------|----------------|---------------|--------------------|
6 col | 600px | 480px | 384px | 100% or auto |
Therefore in as 12-column system handling 3 non-mobile resolutions you would need to calculate a width for each of the 36 different variations. You can probably guess the primary task of Sass here: calculation of specific column widths for each resolution. Rather than having to repeat the loop within each separate media query, Sass actually allows you to nest media queries within a CSS clause, not only making the calculation definition more succint but also making any case-by-case fixes for specific elements much neater.
Using Sass’s mixin functionality, we did away with the unsemantic classes and instead defined the function columns(n) which would explicitly generate the relevant styles needed for a grid-level element:
$grid-width: 60px
$gutter-width: 10px
$columns-count: 12
@function columns-width($n, $width: $grid-width)
@return $n * $width + (($n - 1) * ($gutter-width * 2))
@mixin columns($n)
width: columns-width($n)
margin-left: 10px
margin-right: 10px
float: left
@media only screen and (min-width: 768px) and (max-width: 959px)
width: columns_width($n,44px)
@media only screen and (max-width: 767px)
width: auto
margin-left: 0
margin-right: 0
float: none
For example, consider the following HTML, where .clear is a clearfix for the floating elements:
<div class="clear">
<div id="blurb"></div> <!-- 25% -->
<div id="video"></div> <!-- 75% -->
</div>
<div class="clear">
<div id="info"></div> <!-- 33.3% -->
<div id="map"></div> <!-- 33.3% -->
<div id="social"></div> <!-- 33.3% -->
</div>
Whereas without Sass this would be riddled with extra class definitions, the layout .sass for this is incredibly neat:
#blurb
@include columns(3)
#video
@include columns(9)
#map, #info, #social
@include columns(4)
Grids Within Grids Within Grids
Due to the requirement of a window-wide wrapper behind every level of the layout, we actually nested layout grid elements inside a full-width grid element, i.e. one that used columns(12). Since this effectively cut 20px off the width of the page due to the gutters, we needed to wipe the left gutter off the left-most element, and the right gutter of the right-most element for the grid elements within the wrapper. We did this by defining two mixins, grid_alpha and grid_omega, although these could have easily been classes:
=grid-alpha
margin-left: 0
=grid-omega
margin-right: 0
The best example of this is on this very page, with the article tag being the 12 column element.
<article>
<div class="articlebody"></div>
<aside></aside>
</article>
And the accompanying sass:
article
@include columns(12)
.articlebody
@include columns(8)
+grid_alpha
aside
@include columns(4)
+grid_omega
Classes for Prototyping
When it comes to rapid prototyping, the unsemantic classes can actually be useful, allowing you to quickly create a grid system despite the potential increase in file-size. Wrapping the columns(n) in a loop allows us to easily generate these classes:
@for $i from 1 to ($columns-count)
.grid-#{$i}
@include columns($i)
Once you are happy with your grid and begin to assign more meaningful ids or classes to your elements, you can even use the @extend class to include this in an element's styles rather than just removing the code, as long as you are happy with the larger file-size due to the .grid-n definitions.
In fact, to slightly contradict my earlier statements, the downside to not using classes in your HTML is a larger stylesheet due to potential repetition of the same columns output; so if you are particularly pragmatic about file-size, it might worth testing both methods.
Summary
Of course this is just one take on creating a responsive grid layout with Sass, and in our findings we even discovered several different approaches to creating the grid itself, such as inuit.css and the 978 Grid System, before settling on our particular take. We also discovered some potential flaws in a Sass implementation, as mentioned in the above section.
I would however say that overall the use of Sass definitely had a positive impact on the speed of developing a responsive grid, most obviously making it trivial to adjust the column width to try out larger layouts or changing the number of columns for the same reason. There is always room for optimization however, and I'm sure similar solutions will arise in the coming months.