The modern way of writing media queries with the help of Sass

Everything you know about Media Queries is wrong. Not really, but I kinda felt like that when I dug more into it. Sass (SCSS), of course, does all the dirty work for us.

Lets assume that you have 5 Media Queries, which is an okay amount. You clump them all in the end of your document, declare every Media Query once and put everything you need inside it, right? Wrong.

Sprinkle them in to your code like any styling

Well, smashing them all in the end works really nice, semantic, blazing fast and what not. But, there’s another more modern approach, including Sass of course.

When using Sass, instead of the end clumping, you can pepper the Queries through out the CSS document, places where you would normally put styling related to the given selector. It’s kinda like any styling you apply to a selector. Doing it like this, the Media Queries, get much more intertwined into your coding and the structure of your site, it’s not anymore this separate thing that you throw over you site when everything else is done. This way you are forced to think of it much more, which is a good thing I think.

Apply lavishly like any styling:

.single .column1 {
    width: 100%;
    @media (min-width: 640px) {
        width: 66.66%;
    }
}

Sass spews it out like this:

.single .column1 {
    width: 100%;
}
@media (min-width: 640px) {
    .single .column1 {
        width: 66.66%;
    }
}

Use Mixins and make Sass do the heavy lifting

The before mentiond approach brings a problem with it: you have to define the media queries in many places, if you want to change a width of it, you’re neck deep in shit. Not a desirable position.

The cake eating, and the cake keeping monster Sass to rescue:

@mixin breakpoint($point) {
    @if $point == min-extraextralarge {
        @media screen and (min-width: 1680px) {
            @content;
        }
    }
    @else if $point == min-extralarge {
        @media screen and (min-width: 1443px) {
            @content;
        }
    }
    @else if $point == min-large {
        @media screen and (min-width: 1023px) {
            @content;
        }
    }
    @else if $point == min-medium {
        @media screen and (min-width: 767px) {
            @content;
        }
    }
    @else if $point == min-small {
        @media screen and (min-width: 639px) {
            @content;
        }
    }
}

Now you can sprinkle them all around your CSS where ever you need them!

This code is from this site, it styles the column you’re reading right now:

.single .column1 {
    @include breakpoint(min-medium) {
        width: 66.66%;
    }
    @include breakpoint(min-extralarge) {
        width: 60%;
    }
    width: 100%;
}

What about performance and DRY?

Yes, it’s more code if you use them through out your entire CSS file, opposing to using each one once in the end. In the sense that your file weight few bits more, yes it’s a bad thing. But the gain you get from it is so huge compared to how little more your file weighs.

There is this excellent SassCast article wondering the same thing.

It doesn’t matter what we think of it in our little subjective heads, only thing that really counts is: when you measure it, is it significantly slower? “Let’s ask science!” According to this test scenario it’s not slower.

Shortest possible code is not alway the DRYest or the bestest.

Go mobile first, use min-width not max-width

You noticed that I used min-with rather than max-width. That was also an eye opener for me, work from small to large, not large to small.

The next query says, do stuff to everything that is larger than 640px:

@media (min-width: 640px) {
     /* effects to everything larger than this */
}

This has been the brain fartiest thing in CSS after learning how floats work (back in 2006).

Why in earth would you use min-width?

I quote:

Starting small with min-width reduces redundancy and enables you to focus on structuring your markup logically. It also ensures that many more screen and form factors are taken into account from the beginning as opposed to being an afterthought.

Exactly the point where you entangle the Media Queries to the code to be an interchangeable part of it rather than something glued on. And to endorse the mobile first design strategy is never a bad thing.

This is surprisingly deep and unintuitive thing to grasp. But when grokking it, it feels good and right.

Define Media Queries in ems

You know the zoom in browsers? Quick press of ⌘+ can ruin the layout of your site totally. It’s a thing we’ve been ignoring always. Defining Media Queries in ems will change that and makes the website obey nicely when zoomed.

Zoomed in with px Media Queries:

screengrab 2013-08-31 at 1.49.21 PM

And with em:

screengrab 2013-08-31 at 1.49.43 PM

Enough said I think. Your site adapts to the zoom like it adapts to the screen width.

Clound Four blog has a really nice article about it: The EMs have it: Proportional Media Queries FTW!

How do I get the em values then?

Easy: target size divided by current base size.

If you’ve set your html font size to 100% (more on that):

html {
    font-size: 100%;
}

Then your

  • Current base size is 16px and
  • Target size is the px value you want to convert to em, lets say it’s 640px (iPhone width).
640 / 16 = 40

They can become really wacky easily:

373 / 16 = 23.3125

Better automate it with Sass

Make a function.

// Em conversion
@function calculateEm($size) {
    $remSize: $size / 16px;
    @return #{$remSize}em;
}

Then use it in your breakpoint mixin (mentioned upper):

@mixin breakpoint($point) {
    @if $point == min-extraextralarge {
        @media screen and (min-width: calculateEm(1680px)) {
            @content;
        }
    }
}

Code remains maintainable and zoom doesn’t spoil the site. Nice!

Summary

  1. Sprinkle them in to your code like any styling
  2. Use Mixins and make Sass do the heavy lifting
  3. Go mobile first, use min-width not max-width
  4. Define Media Queries in ems

Club-Mate, the beverage → club-mate.fi