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.