Sass Maps for Breakpoint Mixin (Update)

When I started using Sass, I was using the following breakpoint mixin. It’s pretty simple and common, gets the job done, but could probably be improved.

@mixin breakpoint($point) {
@if $point == small {
@media (min-width: 480px) { @content; }
} @else if $point == medium {
@media (min-width: 720px) { @content; }
} @else if $point == large {
@media (min-width: 960px) { @content; }
} @else if $point == wide {
@media (min-width: 1200px) { @content; }
} @else {
@warn 'Not a valid breakpoint name.';
}
}

I wasn’t really crazy about having the pixel values for the widths in the mixin itself. That data ought to be saved as variables in my _variables.scss, not tucked in _mixins.scss. So I pulled those out and made them variables. This is a little better:

$smallBP: 480px;
$mediumBP: 720px;
$largeBP: 960px;
$wideBP: 1200px;
@mixin breakpoint($point) {
@if $point == small {
@media (min-width: $smallBP) { @content; }
} @else if $point == medium {
@media (min-width: $mediumBP) { @content; }
} @else if $point == large {
@media (min-width: $largeBP) { @content; }
} @else if $point == wide {
@media (min-width: $wideBP) { @content; }
} @else {
@warn 'Not a valid breakpoint name.';
}
}

But what if I get bored with small, medium, large, & wide? (Maybe I’d rather use bears instead…) Or maybe I just want to abstract my breakpoint names to variables too. Sass 3.3 added Sass maps: a clean way to manage an array of variable data.

Now I put all my names and sizes in $breakpoints as a map: each value pair inside holds a breakpoint name and width. This moves all my breakpoint data to a single item in my variables partial.

There’s another big benefit to storing all the breakpoint names and sizes in a map: I can repeat myself less in the mixin itself. In the breakpoint mixin code, I now write the basic structure just once, and let the $breakpoints map data control the previously repeated part.

$breakpoints: (
small: 480px,
medium: 720px,
large: 960px,
wide: 1200px
);
@mixin breakpoint($name) {
@each $label, $size in $breakpoints {
@if $name == $label {
@media (min-width: $size) {
@content;
}
}
}
}

Update: One problem with the code above is that if fails silently. If you misspell your breakpoint name, nothing happens. No errors, no compiled styles. Just failure with no warning. I got some help from Hugo Giraudel in a comment thread. Here’s his suggested rewrite handling errors correctly:

$breakpoints: (
small: 480px,
medium: 720px,
large: 960px,
wide: 1200px
);
@mixin breakpoint($name) {
@if not map-has-key($breakpoints, $name) {
@warn "Warning: `#{$name}` is not a valid breakpoint name.";
} @else {
@media (min-width: map-get($breakpoints, $name)) {
@content;
}
}
}

See the code in action:

Play with this gist on SassMeister.