Nested retina media queries with Sass

Since switching from LESS to Sass I’ve been excited to learn how Sass makes responsive web design easier with @content blocks and @media mixins.

During a recent project I was interested to know if these mixins could be combined and nested with retina based media queries (mq). Could a retina-based mq be nested within a pixel based one? Turns out the answer is yes!

Here’s the media query mixin:

@mixin mq($mq) {
  @if $mq == 690  { @media (max-width: 690px)  { @content; } }
  @if $mq == 320  { @media (max-width: 320px)  { @content; } }

  @if $mq == 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;
    }
  }
}

And here’s the Scss for a logo image replacement. Note the retina mq is nested within the 690 media query:

#site-title a {
  @include hide-text;
  display: block;
  background: url(img/icons/spigot-logo.png) center center no-repeat;
  width: 250px;
  height: 100px;
  position: relative;
  top:5px;
  left: -13px;

    @include mq(retina) {
      background-image: url(img/icons/[email protected]);
      background-size: 250px 100px;
      
    }
    
    @include mq(690) {
      background: url(img/icons/spigot-logo-small.png) center center no-repeat;
      width: 90px;
      height: 125px;
      top: -3px;
      left: -6px;

      @include mq(retina) {
        background-image: url(img/icons/[email protected]);
        background-size: 90px 125px;
      }
    }

After compiling the file I was pleasantly surprised that the code not only worked, but output the final css in a pleasant manner, combining the @media logic into a single query:

@media only screen and (max-width: 690px) and (-webkit-min-device-pixel-ratio: 2), only screen and (max-width: 690px) and (min--moz-device-pixel-ratio: 2), only screen and (max-width: 690px) and (-o-min-device-pixel-ratio: 2 / 1), only screen and (max-width: 690px) and (min-device-pixel-ratio: 2), only screen and (max-width: 690px) and (min-resolution: 192dpi), only screen and (max-width: 690px) and (min-resolution: 2dppx) {
  
  #site-title a {
    background-image: url(img/icons/[email protected]);
    background-size: 90px 125px;
  }
}

Update: A reader emailed me with the following comment:

Good article, but I don’t know why you would write all that code if you could just run the Retina image through ImageOptim and call it a day. I ran the Retina version of your logo (attached) through ImageOptim and it went from 13k to 5k. No loss in quality at all.

— Clint

— Clint

Clint makes a great point – delivering a 5k retina sized image to non retina screens is trivial, and saves the extra css code. I still believe the technique is worth while when delivering larger images.

Photo: Beijing National Stadium

One thought on “Nested retina media queries with Sass

  1. Hello,

    I think the function could be made more reusable by rewriting it to accept any size instead of only pre-defined ones.
    I\’m new to sass so I hope I didn\’t make any mistake in the following rewrite of your function

    @mixin mq($mq) {
    @if $mq == 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;
    }
    } @else {
    @media (max-width: $mqpx) { @content; }
    }
    }

Leave a Reply

Your email address will not be published. Required fields are marked *

Ready for a refreshing experience on your next website design?