A Sass mixin for multiple media queries

Since starting out with Sass I’ve used mixins to avoid having to hand write my media queries. I then used Grunt (and later Gulp) to combine these media queries so I could nest these within the elements they applied to rather than grouping them in a seperate document that made writing and editing the CSS more complicated.

After a while I settled on a mixin that would do the above as well as deal with older browsers by allowing the easy creation of a fixed width stylesheet too. I also used a second mixin for instances where I only required a max-width media query rather than just min-width or min and max together.

The Problem

But none of these could provide the following media query:

@media screen and (min-width:420px) and (max-width:719px), screen and (min-width:980px)

With support for element/container queries still in it’s infancy it can result in having elements that need to flip-flop between two different layouts based on the size of a parent element. Previously with my existing mixins I would duplicate the code and change the pixel measurements as required; this would result in unnecessary duplication of code. The above media query means the code only needs to be included once rather than twice in two different media queries.

The problem occured because when you add that layer of abstraction (Sass) that takes you away from the output code it can be easy to fall into patterns where you don’t consider the alternatives. Seemingly I’d forgetten that I can chain media queries as above so that duplicating the code would be unnecessary. But one day it clicked and all I needed was a mixin to help produce the media query above.

The Solution

Unfortunately for me I couldn’t find an example on the web that solved this particular issue. Either I was trying to fix an issue that no-one else had thought to solve, had solved in a completely different way or I had no clue of what to search for and return the right result. So it was up to me to fix the problem, and then post it here just in case anyone else finds it helpful.

@mixin mq($args){

  $i: 1; // Counter variable to iterate and loop through
  $media: " "; // Empty string variable to concatenate our media queries to

  // Loop our parameter list while counter $i is less than or equal to the number of items in the list
  @while $i <= length($args){

    // If our empty media query string is not empty append a comma and space
    @if $media != " " {
      $media: $media + ", ";
    }

    // If current looping value is 0 (zero) 
    @if nth($args,$i) == 0 {
        
      // Output only a max-width media query using the next value in the list/array
      $media: $media + "screen and (max-width:#{nth($args,$i+1)}px)";
      
    }

    // Else if value is not 0 (zero)
    @else {

      // If counter variable plus one is less than the length of the list/array
      @if $i+1 <= length($args){
          
        // Output media query with both min and max widths
        $media: $media + "screen and (min-width:#{nth($args,$i)}px) and (max-width:#{nth($args,$i+1)}px)";

      }

      // Else if counter variable plus one is more than the length of the list/array
      @else{

        // Only display min-width as no max-width must exist in list/array
        $media: $media + "screen and (min-width:#{nth($args,$i)}px)";

      }
    }

    // Increment counter by two
    $i: $i + 2;

  }

  // If media string variable has contents output media query and contents
  @if $media {
    @media #{$media}{
      @content;
    }
  }

}

This media query is then called as follows:

.class                            {
  $mqs: 380, 719, 1090;
  @include mq($mqs)               {width:auto}
}

So this works by taking an array of values, known as a list in Sass, and iterating through them in batches of two. The first number is the min-width value and the second is the max-width value. The third is min-width and so on

In instances where the min-width number is zero this means that only max-width is used. Where a batch of two numbers has no second or max-width number then only min-width is required. This means the following are all valid array/list values:

$mqs: 0, 419, 720, 949, 1280
$mqs: 0, 359, 640
$mqs: 720, 979, 1280
$mqs: 620, 939
$mqs: 940
$mqs: 0, 299, 300, 399, 400, 499, 500, 599, 600 ...you get the point

I built this mixin to complement the existing mixins on an already completed project so didn’t aim to create something that would do everything the rest do, however it would replace many of the tasks my media query mixins have done. The big thing it won’t do, is allow us to create fixed-width stylesheets by applying only media queries that meet a specified fixed width value. However since we built our old mixin’s that do this we have largely dropped support for browsers that don’t support media queries so this functionality is now only required in rare circumstances and so isn’t required in this mixin.


We'd love to hear from you!

If you think Bronco has the skills to take your business forward then what are you waiting for?

Get in Touch Today!

Discussion

Add a Comment