Getting Started with Sass and Breakpoint Mixin
Are you one of those people that love your CSS and take pride in crafting a CSS document? If so the chances are that you also haven’t taken the leap into CSS preprocessors because of this exact reason.
My colleague Chris was one of those people until recently and is currently finding the delight that comes with scss over css. My one tip for him when he got started was to break up his Sass files into modules by creating _module.scss
files, and to use a breakpoint mixin to write the media query changes to the module inline with the rest of the rules. Chris is now much happier with life, so let’s take a look at what I’m talking about in more detail.
Structuring your Sass
When I first started working with Sass I set my project up in the same way that I would usually approach my standard CSS file.
- Normalise
- Typographical
- Layout
- General
- @media query overrides
This converted to my .scss file to look like this
@import "normalise";
@import "typography";
@import "layout";
@import "screen";
@import "layout";
@media (min-width:37.5em){
@import "37_5ems";
}
@media (min-width:50em){
@import "50ems";
}
@media (min-width:64em){
@import "64ems";
}
@import "junk";
The issue with this approach was that while I was working on the header of the iste I was styling the logo, navigation, breadcrumbs, search. Once I had them sorted I would fix any issues in each of the separate media query files.
While this gave me the benefit of only declaring the media query once in my final markup, it proved to be difficult to remember what changes were made at each breakpoint for the particular module.
Nearly half way through I realised there was an easier approach to this problem.
By creating a mixin in Sass I could separate my modules into their own .scss files rather the separating the media queries, and the media queries could be declared inline with each module.
Here’s how it works.
Create .scss files for each module
In my example this was
- _grid.scss – all grid declarations
- _icons.scss – all icon declarations
- _search.scss – all search module layouts
- _header.scss – declare the header elements
- _articles.scss – declare any article specific layouts
- _resources.scss – declare the resources layout
- … more…
Create an _bits.scss file
This file will contain all my variables and mixins, here is an example of the variables.
/*********************
VARIABLES
*********************/
$red: #cc4e46;
$pale: #ede6dc;
$lightpale: #f2ece5;
$paleborder: #eee7dd;
$palefootertext: #d2d0c2;
$modulebackground: #d0cdc4;
$dark: #333;
Breakpoint Mixins to the rescue
The mixin below declares the name of the breakpoint along with the associated rules for that breakpoint. For this site I’ve built mobile first and declared phablets, tablets, laptops and desktops as the breakpoint names, which corresponds to 37.5, 50, 64 and 70ems respectively. I should pointout that I’ve got a mobileonly declaration in there for devices with a max width of 37.5ems however that was more to do with fixing mistakes then anything else.
/*********************
VARIABLES
*********************/
$red: #cc4e46;
$pale: #ede6dc;
$lightpale: #f2ece5;
$paleborder: #eee7dd;
$palefootertext: #d2d0c2;
$modulebackground: #d0cdc4;
$dark: #333;
/*********************
BREAKPOINTS
*********************/
@mixin breakpoint($point) {
@if $point == desktop {
@media (min-width: 70em) { @content ; }
}
@else if $point == laptop {
@media (min-width: 64em) { @content ; }
}
@else if $point == tablet {
@media (min-width: 50em) { @content ; }
}
@else if $point == phablet {
@media (min-width: 37.5em) { @content ; }
}
@else if $point == mobileonly {
@media (max-width: 37.5em) { @content ; }
}
}
Once declared you can use the following syntax to insert a media query anywhere within your SCSS.
@include breakpoint(breakpointname) {
/* Styles */
}
This allows me to then declare an entire module — with overriding media queries — all in the one place.
In the _grids.scss
file I can now declare the following…
.grid-1-4 {
width: 100%;
@include breakpoint(phablet) {
width: 50%;
}
@include breakpoint(laptop) {
width: 25%;
}
}
.grid-1-3 {
width: 100%;
@include breakpoint(phablet){
width:33.3%;
min-height:290px;
}
}
.grid-1-2 {
width: 100%;
@include breakpoint(tablet){
width:50%;
}
}
… which turns into the following CSS after processing.
.grid-1-4 { width: 100%; }
@media (min-width: 37.5em) { .grid-1-4 { width: 50%; } }
@media (min-width: 64em) { .grid-1-4 { width: 25%; } }
.grid-1-3 { width: 100%; }
@media (min-width: 37.5em) { .grid-1-3 { width: 33.3%; min-height: 290px; } }
.grid-1-2 { width: 100%; }
@media (min-width: 50em) { .grid-1-2 { width: 50%; } }
Won’t I have the same media query declared a million times?
Probably not a million times… and if that were true then this is certainly not your first problem.
Sure, you’re going to be repeating a tonne of media queries that will add to the size of your CSS file. Fortunately you can enable GZIP compression on your server which will take all of those repeatable media query chunks and practically make them vanish.