1939Days

1939 days since this post was last revised. Specific details are likely out of date.

A few months back I wrote an article for .net magazine about the upcoming Sass 3.2 release (details bottom right of that link) and the way you can use media queries with it. I was inspired pricipally by a Gist I’d seen by core team member Chris Eppstein. It basically allowed you to pass content blocks to mixins. More of this shortly…

Now, I wasn’t the first to look at this stuff, I’m pretty sure Jeff Croft was one of the first to start using it, then Mason Wendell and I’m sure plenty of others…

The other night I had a peek at CSS-tricks site (always a good read) and Mr Chris Coyier had added a post about Sass 3.2 and getting it to play happily with CodeKit. That reminded me to add something here about how you can also use this with LiveReload.

I’ve used Sass 3.2 and LiveReload together for 2 production projects and it has been superb. I prefer writing my media queries this way. Here’s how it works and how you can get using it.

First off, if you haven’t already, you’ll want to get Sass 3.2 installed. It’s pre-release at present but I’ve found it to be entirely stable. Enter this in terminal (‘sudo’ often necessary on OSX): sudo gem install sass --pre. Now, onwards…

Building a responsive site

OK, so ordinarily, when writing the styles for a responsive site, you write a baseline set of ‘accessibility styles’ – this can be seen by pretty much any device. Basic typography, colours and a sprinkling of CSS3 etc
Then within media queries we add all the layout styles. Number of columns, widths etc at the various design breakpoints.
However, the joyous thing about doing this with Sass is that you don’t have to repeat styles inside a sectioned-off media query partial. For example. With CSS you might do this:

.element {
	color: #ebebeb;
	background: #fff;
}
.element2 {
	color: #fff;
	font-size: 2em;
}
.thing {
	list-style: none;
}
/* ==========================================================================
   Lots more styles
   ========================================================================== */

@media screen and (min-width: 600px) {
	.element {
		width: 70%;
	}	
}

@media screen and (min-width: 400px) {
	.element {
		width: 100%;
	}	
}

However, with Sass 3.2, instead of sectioning of all the media queries into a partial file you can write them inline. What’s more, you can write a mixin and pass some content to it. So with Sass 3.2 I would write this to achieve the same objective:

.element {
	color: #ebebeb;
	background: #fff;
	@include MQ(XXLneg) {
		width: 70%;
	}
	@include MQ(XXLplus) {
		width: 100%;
	} 
}
.element2 {
	color: #fff;
	font-size: 2em;
}
.thing {
	list-style: none;
}

Instead of a partial containing all the media queries, I write a _MQ partial file. It includes something like this:

//variables
$XS: 280px;
$S: 320px;
$M: 480px;
$L: 600px;
$XL: 768px;
$XXL: 980px;

//mixin
@mixin MQ($canvas) {
  @if $canvas == XS {
    @media only screen and (min-width: $XS) and (max-width: $S - 1) { @content; }
  }
  @else if $canvas == S {
    @media only screen and (min-width: $S) and (max-width: $M - 1) { @content; }
  }
  @else if $canvas == M {
    @media only screen and (min-width: $M) and (max-width: $L - 1) { @content; }
  }
  @else if $canvas == L {
    @media only screen and (min-width: $L) and (max-width: $XL - 1) { @content; }
  }
  @else if $canvas == XL {
    @media only screen and (min-width: $XL) and (max-width: $XXL - 1) { @content; }
  }
  @else if $canvas == XXL {
    @media only screen and (min-width: $XXL) { @content; }
  }
  @else if $canvas == XSplus {
    @media only screen and (min-width: $XS) { @content; }
  }
  @else if $canvas == Splus {
    @media only screen and (min-width: $S) { @content; }
  }
  @else if $canvas == Mplus {
    @media only screen and (min-width: $M) { @content; }
  }
  @else if $canvas == Lplus {
    @media only screen and (min-width: $L) { @content; }
  }
  @else if $canvas == XLplus {
    @media only screen and (min-width: $XL) { @content; }
  }
  @else if $canvas == XXLplus {
    @media only screen and (min-width: $XXL) { @content; }
  }
  @else if $canvas == XSneg {
    @media only screen and (max-width: $XS) { @content; }
  }
  @else if $canvas == Sneg {
    @media only screen and (max-width: $S) { @content; }
  }
  @else if $canvas == Mneg {
    @media only screen and (max-width: $M) { @content; }
  }
  @else if $canvas == Lneg {
    @media only screen and (max-width: $L) { @content; }
  }
  @else if $canvas == XLneg {
    @media only screen and (max-width: $XL) { @content; }
  }
  @else if $canvas == XXLneg {
    @media only screen and (max-width: $XXL) { @content; }
  }
  @else if $canvas == StoL {
    @media only screen and (min-width: $S) and (max-width: $L - 1) { @content; }
  }
}

Those variables can be whatever you like, whether you are using pixels or ems for the job (you can even have the variables in a separate partial file if you like all your variables defined in one place) and should change from design to design.

Now, after including that partial (e.g. @import "partials/MQ";) it’s possible to write media queries anywhere in the document, easily altering styles for every breakpoint.

Size concerns?

I was a little concerned about this leading to an enormous CSS file with media queries strewn throughout. The output CSS certainly doesn’t look as neat but my experience has been that once compressed for production and sent gzipped it’s a non-issue. I’d welcome feedback from anyone who can prove otherwise.

Sass 3.2 and LiveReload

I always used to compile Sass to CSS by using the command line but I now use LiveReload. However, the ‘stable’ version (3.2.8 at the App Store at the time of writing) doesn’t play happily with Sass 3.2 media queries. Therefore, I’d suggest using version 2.3.6 (available by choosing the version from the GitHub tags here).

Just use that and then you can get writing Sass 3.2 style media queries to your hearts content.

UPDATE – I spoke to Andrey, developer of the wonderful LiveReload and he pointed out that every version of LiveReload since 3.2.12 actually has the pre-release version of Sass 3.2 Alpha baked in. You can grab the latest version (3.2.18 at time of writing) here: http://go.livereload.com/intro. Note however that includes the latest version of Susy too (v1.0), so if you have sites written with the old pre-release version of Susy, tread carefully.

Andrey has also included the following information regarding how to use different versions of Sass and the like with LiveReload:

A friendly UI for choosing versions of your SASS, LESS etc preprocessors is coming. Meanwhile, here are your options of using a version different from the one shipped with LiveReload:

Option 1. Try the latest beta version — it usually contains the latest released (aka stable) versions of all preprocessors.

Option 2. Inside LiveReload.app bundle, delete all gems under e.g. Resources/SASS.lrplugin/lib/; deleting bundled gems will force LiveReload to use the gems from your system. (If you are using RVM, be sure that the correct version of Ruby is specified in Compilation Settings.)

Option 3. Instead of deleting the gems, you can update them to the latest versions. Optionally, before customizing it, you may copy SASS.lrplugin into ~/Library/LiveReload/Plugins so that your custom version will survive LiveReload updates.

Just one more thing…(placeholder)

Another cracking feature of Sass 3.2 is ‘placeholders’. Rather than use @extend to extend a real, existing style, you can use a placeholder. Here’s an example of how I’m using them day to day. At the top of my file I add a list of my ‘placeholders’. Here’s one for a site I’m working on:

%br12 {
  @include border-radius(12px);
}

Now, when I need to add a 12px border radius to a style I can do this:

.element {
  @extend %br12
  /* other styles */
}

It kind of reminds me of OOCSS but it’s really just a convenience thing. So if there is some syntax you can never remember, just make a placeholder for it (that you can remember) and you’re good to go.

Ben Frain Developer, Author: 'Enduring CSS', 'Responsive Web Design with HTML5 & CSS3'.