Product Design Lessons

Intro to Foundation  |   Lesson #40

Master Media Queries With Sass

Learn to edit multiple media queries with a few Sass variables.

No media query is an island unto itself. Several often work together to create the appropriate styles for different scenarios — smartphones, tablets and desktop browsers, and even different screen orientations. You have to worry about conflicting ranges. You have to write redundant code. You have to hunt for queries through dozens or hundreds of lines in CSS. Overall, media queries in complex products can be a pain. 

But they don't have to be. Sass makes media queries a snap with very little setup. Here's how you can use Sass variables to master media queries.

Look at regular media queries

Here's a typical setup in plain CSS:

@media screen and (max-width:40em) { … }

@media screen and (min-width: 40.063em)
  and (max-width: 64em) { … }

@media screen and (min-width: 64.063em)
  and (max-width: 120em) { … }

@media screen and (min-width: 120.063em) { … }

This code creates four ranges: 0–40em, 40.063–64em, 64.063–120em, and 120.063+ em. Trouble is, each { … } could stand for hundreds of lines of CSS. Adjusting widths from 40em to, say, 42 poses a problem. This is what we want Sass to handle for us.

1. Define your ranges

A range is the space between breakpoints — while a breakpoint might be 10em, for example, 10–20em defines everything between 10 and 20. In this case, our ranges look like this:

$small-range: ( 0em, 40em );
$medium-range: ( 40.063em, 64em );
$large-range: ( 64.063, 120em );

We prevent overlaps at each breakpoint by adding 0.063 — approximately one pixel when the default font size is 16pt — to each minimum width.

diagram showing how using the same number creates overlapping rules

Above: Overlaps occur when two ranges, like 0–40 and 40–80, have a pixel of overlap. At that point, browsers don't know which set of rules to apply. When we make one just slightly different — in this case adding 0.063em — ranges become unambiguous.

2. Add ranges to media queries

The next step sets up ranges to become media queries.

$small-query: "#{$screen} and
  (max-width: #{upper-bound($small-range)})";

$medium-query: "#{$screen}
  and (min-width:#{lower-bound($medium-range)})
  and (max-width:#{upper-bound($medium-range)})";

$large-query: "#{$screen}
  and (min-width:#{lower-bound($large-range)})
  and (max-width:#{upper-bound($large-range)})";

3. Add code to media queries

Notice that this isn't CSS yet — browsers don't read SCSS itself. We're just setting up the code for the queries themselves, which we define next:

@media screen and #{$small-query} { … }
@media screen and #{$medium-query} { … }
@media screen and #{$large-query} { … }

When compiled you'll get:

@media only screen
  and (max-width: upper-bound(0em, 42em)) { … }

@media only screen
  and (min-width: lower-bound(42.063em, 64em))
  and (max-width: upper-bound(42.63em, 64em)) { … }

@media only screen
  and (min-width: lower-bound(64.063em, 90em))
  and (max-width: upper-bound(64.063em, 90em)) { … }

4. Adjust on the fly

Let's say we decide that 0–40em isn't right. Maybe we want, say, 0–42em instead. Using the first variables we defined, you can change both the small range (0–40em) and bump up the medium range to accommodate the change.

$small-range: ( 0em, 42em );
$medium-range: ( 42.063em, 64em );
$large-range: ( 64.063, 120em );

This one change will result these media queries:

@media only screen and (max-width: 42em)) { … }

@media only screen
  and (min-width: 42.063em)
  and (max-width: 42.063em, 64em) { … }

@media only screen
  and (min-width: 64.063em)
  and (max-width: 64.63em) { … }

Actually, when we think mobile-first, the first media query is redundant — all styles should apply except for medium and large screens. But the small query is helpful for debugging.

A practical example

Let's apply this to a real site. Pure Fix Bikes has several breakpoints that we could use Foundation's medium- and large-block grids to create.

example of a medium grid

Above: We could use the medium block grid to arrange images in two different rows.

example of a wide grid

Above: Meanwhile the large block grid creates a different layout arrangement, which adds even more non-semantic code to the page.

To make this semantic, we start by creating two sets of elements:

.menu { } .item-list { }

Into that we add Foundation's block grid:

.menu {
@include block-grid(1);
}
.item-list {

@include block-grid(1);
}

These includes will create a single-block-wide layout, which works well on mobile devices. Next we add Foundation's built-in $medium-up media query to override that in medium-sized screens:

.menu {
@include block-grid(1);

@media #{$medium-up} {
@include block-grid(2);
}
}
.item-list {
@include block-grid(1);

@media #{$medium-up} {
@include block-grid(3);
}
}

Finally, we add a media query to push the menu to four items in large viewports. (Remember that the item-list remains three blocks wide.)

.menu {
text-align: center;
@include block-grid(1);
@media #{$medium-up} {
@include block-grid(2);
}

@media #{$large-up} {
@include block-grid(4);
}
}
.item-list {
@include block-grid(1);
@media #{$medium-up} {
@include block-grid(3);
}
}

And that's it. The more complicated a product's CSS becomes, the more important variables are. This technique keeps you from digging through hundreds of lines to keep track of media queries' ranges, especially when you organize your SCSS into parts that use the same query values repeatedly.


About the instructor

Ben

Ben Gremillion is a Design Writer at ZURB. He started his career in newspaper and magazine design, saw a digital future, and learned HTML in short order. He facilitates the ZURB training courses.