Write Better Media Queries with Sass
Let's face facts: media queries can be a pain. They're difficult to write and they tend to get duplicated a lot. Sass includes a few helpful features that make media queries easier to work with. This article will show you these tricks and how you can use them to simplify your stylesheets.
The Basics
Let's take a look at a simple example.
p { font-size: 16px; } @media (min-width: 768px) and (max-width: 1023px) { p { font-size: 18px; } } @media (min-width: 1024px) { p { font-size: 20px; } }
Here, we've set the font size of paragraphs to 16 pixels. When the viewport width is greater than or equal to 768 pixels, and less than or equal to 1023 pixels, the font size is 18 pixels. When the viewport is greater than or equal to 1024 pixels, the font size is 20 pixels.
Right away, you should be struck by how much code is required to do something as simple as responsive typography. As projects grow larger, the above style of writing media queries usually leads in one of two directions:
- Media queries are hardcoded in the code and copied where they're needed. If we want to change a media query, we have to do it in many places.
- The project is split up by viewport sizes. It's jarring and time-consuming to jump to multiple places to update a single element's styles.
Shortening Things Up
Sass allows variables to be interpolated. This means that we can move our media queries into variables and reuse them.
$tablet: "(min-width: 768px) and (max-width: 1023px)"; $desktop: "(min-width: 1024px)"; p { font-size: 16px; } @media #{$tablet} { p { font-size: 18px; } } @media #{$desktop} { p { font-size: 20px; } }
Now, we can use the $tablet
and $desktop
media queries anywhere in our project without duplicating code. However, it's still annoying that our media queries are separate from the code they style. The Sass folks fixed this problem by allowing media queries to be nested.
$tablet: "(min-width: 768px) and (max-width: 1023px)"; $desktop: "(min-width: 1024px)"; p { font-size: 16px; @media #{$tablet} { font-size: 18px; } @media #{$desktop} { font-size: 20px; } }
Mixins to the Rescue
The code above works, but it's a bit difficult to read. We can clean it up by using Sass's mixins. Mixins are groups of styles that can be reused throughout your code. One of the nifty features of mixins is they can use blocks of content. This lets us write mixins like this:
$tablet-width: 768px; $desktop-width: 1024px; @mixin tablet { @media (min-width: #{$tablet-width}) and (max-width: #{$desktop-width - 1px}) { @content; } } @mixin desktop { @media (min-width: #{$desktop-width}) { @content; } }
Now, we can rewrite our example above to use these new mixins.
p { font-size: 16px; @include tablet { font-size: 18px; } @include desktop { font-size: 20px; } }
We're not just limited to device sizes. We can write media queries for many other useful things, such as Chris Coyier's retina media query or a print media query.
@mixin retina { @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) { @content; } } @mixin print { @media print { @content; } }
Wrapping Up
Media queries are great, and with Sass they can be even better. The next time you use one, remember these tricks to help make your code more readable and easier to maintain.
About Landon Schropp
Landon is a developer, designer and entrepreneur based in Kansas City. He's the author of the Unraveling Flexbox. He's passionate about building simple apps people love to use.
Thank you.
I think the code be heavy with this way, isn’t it?
and compiled:
Yes, it’s slightly more code. However, I feel like optimizing at this level isn’t worth the effort unless you’re at a massive scale. Check out this post for more details: http://fourword.fourkitchens.com/article/one-less-jpg
post-css has a package called css-mqpacker that will combine the duplicated media queries into one block. This will reduce the size of the css while allowing engineers to still use the mixins. https://www.npmjs.com/package/css-mqpacker
I’m using a respond-mixing
@import respond-to('medium')
and a breakpoint-configuration in order to handle the media queries.https://github.com/macx/sass-mixins/blob/master/src/_layout/_respond.scss
This is great and it’s easier to read, but could potentially bloat your code a lot, adding each breakpoint under it’s selector increases file size considerably, specially on large scale sites. I’m not saying this is a bad idea for pre-compiled code, but it’d be very useful if SASS could group all breakpoints into groups.
@brian, I don’t think that is actually an issue once the CSS is GZIP’d. It’s good at handling things like that.
@Brian, gulp-cssmin can do that (https://github.com/chilijung/gulp-cssmin), it groups all similar pieces of CSS into buckets. The code isn’t readable but it helps to reduce it’s size.
Here is an alternative http://codepen.io/dsheiko/pen/KeLGy
It works like that:
I was looking for a good way to solve media queries with retina-display and dpi and this looks quite good!
Thanks for sharing :)
Excellent post. I prefer this method to structuring our files by breakpoint type. When files are structured by breakpoint you can end up with some developers in a team adding duplicate code because of improper overriding or difficulty finding the correct location of code.
Also, it seems with gzip the bloat of extra media queries is minimal.
http://sasscast.tumblr.com/post/38673939456/sass-and-media-queries
Hey, we started using this solution in our team. We found it works really well! https://davidwalsh.name/write-media-queries-sass
Note that you can do like that
($laptop, $desktop)
:I like that!
In my case i have
$mobile
,$tablet
and$desktop
. What if i have to write down media query for$not_mobile
, do you mixin for this?mq-scss is the most powerful media query mixin I’ve come across.
https://www.npmjs.com/package/mq-scss
You can do crazy stuff like this:
That’s a bit of a ridiculous example but it shows off a lot of mq-scss’s features.
why we write # before {$laptop} what was the use..?
can you please explain me.
It’s a small thing… but wouldn’t most people want to carry this style through the horizontal tablet view?
And then start the larger size at 1025, not 1024?