<style>
  .include-media-test {
    width: 100%;
    height: 200px;
    line-height: 100px;
    text-align: center;
    font-size: 20px;
    font-family: Helvetica;
  }
  
  .include-media-test:after {
    display: block;
    content: "Non-retina";
  }
</style>
<div class="include-media-test"></div>
@import "compass/css3";

//  	 _            _           _                           _ _       
//  	(_)          | |         | |                         | (_)      
//  	 _ _ __   ___| |_   _  __| | ___   _ __ ___   ___  __| |_  __ _ 
//  	| | '_ \ / __| | | | |/ _` |/ _ \ | '_ ` _ \ / _ \/ _` | |/ _` |
//  	| | | | | (__| | |_| | (_| |  __/ | | | | | |  __/ (_| | | (_| |
//  	|_|_| |_|\___|_|\__,_|\__,_|\___| |_| |_| |_|\___|\__,_|_|\__,_|
//
//			Simple, elegant and maintainable media queries in Sass
//
//			 			http://include-media.com
//		
//	  		 Author: Eduardo Boucas <mail@eduardoboucas.com>
//
///
/// Creates a list of global breakpoints
///
/// @author Eduardo Boucas
///
/// @example scss - Creates a single breakpoint with the label `phone`
///  $breakpoints: ('phone': 320px);
///
$breakpoints: (
	'phone': 320px, 
	'tablet': 768px, 
	'desktop': 1024px
) !default;

///
/// Creates a list of static expressions or media types
///
/// @author Eduardo Boucas
///
/// @example scss - Creates a single media type (screen)
///  $media-expressions: ('screen': 'screen');
///
/// @example scss - Creates a static expression with logical disjunction (OR operator)
///  $media-expressions: (
///		'retina2x': (
///			'(-webkit-min-device-pixel-ratio: 2)', 
///			'(min-resolution: 192dpi)'
///		)
///	);
///
$media-expressions: (
	'screen': 'screen', 
	'print': 'print', 
	'handheld': 'handheld',
	'retina2x': (
		'(-webkit-min-device-pixel-ratio: 2)', 
		'(min-resolution: 192dpi)'
	), 
	'retina3x': (
		'(-webkit-min-device-pixel-ratio: 3)', 
		'(min-resolution: 350dpi)'
	)
) !default;

///
/// Defines a number to be added or subtracted from each unit when declaring breakpoints with exclusive intervals
///
/// @author Eduardo Boucas
///
/// @example scss - Interval for pixels is defined as `1` by default
///  @include media(">128px") {}
///
///	 /* Generates: */
///	 @media (min-width: 129px) {}
///
/// @example scss - Interval for ems is defined as `0.01` by default
///  @include media(">20em") {}
///
///	 /* Generates: */
///	 @media (min-width: 20.01em) {}
///
/// @example scss - Interval for rems is defined as `0.1` by default, to be used with `font-size: 62.5%;`
///  @include media(">2.0rem") {}
///
///	 /* Generates: */
///	 @media (min-width: 2.1rem) {}
///
$unit-intervals: (
	'px': 1, 
	'em': 0.01, 
	'rem': 0.1
) !default;
///
/// Generates a media query based on a list of conditions
///
/// @author Eduardo Boucas
///
/// @param {List}   $conditions  - Media query conditions
///
/// @example scss - With a single set breakpoint
///  @include media(">phone") { }
///
/// @example scss - With two set breakpoints
///  @include media(">phone", "<=tablet") { } 
///
/// @example scss - With custom values
///  @include media(">=358px", "<850px") { } 
///
/// @example scss - With set breakpoints with custom values
///  @include media(">desktop", "<=1350px") { } 
///
/// @example scss - With a static expression
///  @include media("retina2x") { } 
///
/// @example scss - Mixing everything
///  @include media(">=350px", "<tablet", "retina3x") { } 
///
@mixin media($conditions...) {
  @for $i from 1 through length($conditions) {
    $conditions: set-nth($conditions, $i, parse-expression(nth($conditions, $i)));
  }

  $branches: get-query-branches($conditions);
  $query: '';

  @each $branch in $branches {
    @if (str-length($query) != 0) {
      $query: $query + ', ';
    }

    $query: $query + $branch;
  }

  @media #{$query} {
    @content;
  }
}

///
/// Reads a list of media query expressions and separates logical disjunctions into different branches
///
/// @author Eduardo Boucas
///
/// @param {List}   $expressions  - list of expressions
///
/// @throws `$expression` is not a valid expression
///
/// @return {List | Null}
///
@function get-query-branches($expressions) {
  $result: '';
  $has-groups: false;

  // Getting initial snapshot and looking for groups
  @each $expression in $expressions {
    @if (str-length($result) != 0) {
      $result: $result + ' and ';
    }

    @if (type-of($expression) == 'string') {
      $result: $result + $expression;
    } @else if (type-of($expression) == 'list') {
      $result: $result + nth($expression, 1);
      $has-groups: true;
    } @else {
      @warn '#{$expression} is not a valid expression.';
    }
  }

  // If we have groups, we have to create all possible combinations
  @if $has-groups {
    @each $expression in $expressions {
      @if (type-of($expression) == 'list') {
        $first: nth($expression, 1);

        @each $member in $expression {
          @if ($member != $first) {
            @each $partial in $result {
              $result: join($result, str-replace-first($first, $member, $partial));
            }
          }
        }
      }
    }
  }

  @return $result;
}

///
/// Parses a string to form a media query expression
///
/// @author Eduardo Boucas
///
/// @param {String}   $expression  - expression (in string)
///
/// @throws Expression with type `type-of($expression)` detected, string expected
/// @throws `$expression` is missing an operator
/// @throws Unknown unit: `$unit`
///
/// @return {String | Null}
///
@function parse-expression($expression) {
  $operator: '';
  $value: '';
  $element: '';
  $result: '';
  $is-width: true;

  @if (type-of($expression) != 'string') {
    @warn 'Expression with type `#{type-of($expression)}` detected, string expected.';
  }

  // Separating the operator from the rest of the expression
  @if (str-slice($expression, 2, 2) == '=') {
    $operator: str-slice($expression, 1, 2);
    $value: str-slice($expression, 3);
  } @else {
    $operator: str-slice($expression, 1, 1);
    $value: str-slice($expression, 2);
  }

  // Checking what type of expression we're dealing with
  @if map-has-key($breakpoints, $value) {
    $result: map-get($breakpoints, $value);
  } @else if map-has-key($media-expressions, $expression) {
    $result: map-get($media-expressions, $expression);
    $is-width: false;
  } @else {
    $result: to-number($value);
  }

  @if ($is-width) {
    $unit: unit($result);
    $interval: 0;
    
    @if (map-has-key($unit-intervals, $unit)) {
      $interval: map-get($unit-intervals, $unit);
    } @else {
      @warn 'Unknown unit: #{$unit}';
    } 
       
    @if ($operator == '>') {
      $element: '(min-width: #{$result + $interval})';
    } @else if ($operator == '<') {
      $element: '(max-width: #{$result - $interval})';
    } @else if ($operator == '>=') {
      $element: '(min-width: #{$result})';
    } @else if ($operator == '<=') {
      $element: '(max-width: #{$result})';
    } @else {
      @warn '#{$expression} is missing an operator.';
    }
  } @else {
    $element: $result;
  }

  @return $element;
}

///
/// Replaces the first occurence of the string with the replacement string
///
/// @author Eduardo Boucas
///
/// @param {String}   $search  - The value being searched for
/// @param {String}   $replace  - The replacement string
/// @param {String}   $subject  - The string being replaced on
///
/// @return {String | Null}
///
@function str-replace-first($search, $replace, $subject) {
  $search-start: str-index($subject, $search);

  @if $search-start == null {
    @return $subject;
  }

  $result: str-slice($subject, 0, $search-start - 1);
  $result: $result + $replace;
  $result: $result + str-slice($subject, $search-start + str-length($search));

  @return $result;
}

///
/// Casts a number to a string
///
/// @author Hugo Giraudel
///
/// @param {String}   $string  - Number to be parsed
///
/// @return {List | Null}
///
@function to-number($string) {
  // Matrices
  $strings: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9';
  $numbers:  0   1   2   3   4   5   6   7   8   9;
  
  // Result
  $result: 0;
  $divider: 0;
  $minus: false;

  // Looping through all characters
  @for $i from 1 through str-length($string) {
    $character: str-slice($string, $i, $i);
    $index: index($strings, $character);
    
  
    @if $character == '-' {
      $minus: true;
    }
    
    @else if $character == '.' {
      $divider: 1;
    }
    
    @else {
      @if type-of($index) != 'number' {
        $result: if($minus, $result * -1, $result);
        @return _length($result, str-slice($string, $i));
      }

      $number: nth($numbers, $index);
      
      @if $divider == 0 {
        $result: $result * 10;
      }
      
      @else {
        // Move the decimal dot to the left
        $divider: $divider * 10;
        $number: $number / $divider;
      }
      
      $result: $result + $number;
    }
  }
  
  @return if($minus, $result * -1, $result);
}

@function _length($number, $unit) {
  $strings: 'px' 'cm' 'mm' '%' 'ch' 'pica' 'in' 'em' 'rem' 'pt' 'pc' 'ex' 'vw' 'vh' 'vmin' 'vmax';
  $units:   1px  1cm  1mm  1%  1ch  1pica  1in  1em  1rem  1pt  1pc  1ex  1vw  1vh  1vmin  1vmax;
  $index: index($strings, $unit);
  
  @if type-of($index) != 'number' {
    @warn 'Unknown unit `#{$unit}`.';
    @return false;
  }
  
  @return $number * nth($units, $index);
}

/**
*
* Testing
*
**/

.include-media-test {
  @include media("<=phone") {
    background-color: #def;
    
    &:before {
      content: "<=phone";
    }
  }

  @include media(">phone") {
    background-color: #abc;
    
    &:before {
      content: ">phone";
    }    
  }

  @include media(">=815px", "<desktop") {
    background-color: #fed;
    
    &:before {
      content: ">=815px, <desktop";
    }    
  }

  @include media(">=desktop") {
    background-color: #fab;
    
    &:before {
      content: ">=desktop";
    }
  }
  
  @include media("retina2x") {
    &:after {
      content: "Retina" !important;
    }    
  }
}
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.