Using Media Queries in Sass 3.2

    With the release of Sass 3.2, the Object Oriented CSS (OOCSS) path began to advance into the masses, bringing with it the DRY principle and programmatic thinking. Media queries and OOCSS have become vital to today's front-end development.



    Let's see what's new


    Sass has very useful functionality, not widely known content . You can think of content as yield — it allows us to define sass @mixin, which has nested CSS. This will save valuable hours and reduce code repetition and greatly simplify work with media queries.

    How it works


    First you need to declare variables that will determine the entry points for devices and add an abstraction layer to our media queries. To do this, create @mixin respond-to:

    $small: 320px;
    $large: 1024px;
    @mixin respond-to($media) {
      @if $media == handhelds {
        @media only screen and (max-width: $small) { @content; }
      }
      @else if $media == medium-screens {
        @media only screen and (min-width: $small + 1) and (max-width: $large - 1) { @content; }
      }
      @else if $media == wide-screens {
        @media only screen and (min-width: $large) { @content; }
      }
    }
    .block {
      float: left;
      width: 250px;
      @include respond-to(handhelds) { width: 100% ;}
      @include respond-to(medium-screens) { width: 125px; }
      @include respond-to(wide-screens) { float: none; }
    }​
    

    The code is better read and instantly more meaningful than decryption, for example, media only screen and (max-width: 320px) and (orientation: portrait).
    All the magic lies in content , which allows us to pass into CSS the properties that we want to apply in accordance with the media request above. We cannot know what design will require in the future, but through this abstraction it will be easy to update styles when these changes occur.
    After compiling Sass, we get the CSS you need:

    .block {
      float: left;
      width: 250px;
    }
    @media only screen and (max-width: 320px) {
      .block {
        width: 100%;
      }
    }
    @media only screen and (min-width: 321px) and (max-width: 1023px) {
      .block {
        width: 125px;
      }
    }
    @media only screen and (min-width: 1024px) {
      .block {
        float: none;
      }
    }​
    

    If you need to use CSS, for anything less than ipad-lanscape, for example, then you can not paint the respond-to variations, but make a new @mixin that will be adapted for different devices:

    $ipad-landscape: 980px;
    @mixin apply-to($ltgt, $device) {
      $extrema: null;
      @if $ltgt == less-than {
        $extrema: max;
      }    
      @if $ltgt == greater-than {
        $extrema: min        
      } 
      @if $device == $ipad-landscape {
        @media only screen and (#{$extrema}-width: $ipad-landscape) {
          @content;
        }
      }
    }
    .block {
      @include apply-to(less-than, ipad-landscape) {
        background: black;
      }  
    }​
    

    What problems can be encountered


    All this is very fine and allows you to make interesting interfaces, but it will not work in IE below the ninth version. The solution to the problem is to generate separate style files:


    The file for IE declares the variables $old-ie: true;and necessary width fixation and imports the main style file. In the main style file, IE $ old-ie variables will default to false. You will need to write @mixin for IE and extend the apply-to functionality:

    @mixin old-ie {
      @if $old-ie {
        @content;
      }
    }
    @mixin apply-to($ltgt, $device) {
      $extrema: null;
      @if $ltgt == less-than {
        $extrema: max;
      }    
      @if $ltgt == greater-than {
        $extrema: min        
      } 
      @if $fix-mqs-ipad-landscape {
        @content;
      }
      @else {     
        @media screen and (#{$extrema}-width: $device) {
          @content;
        }
      }
    }
    .block {
        @include apply-to(less-than, $ipad-landscape) {
            float: left;
            width: 70%;
            @include old-ie {
                content: 'Все то, что может понадобиться для IE';
            }
        }
    }
    

    There are also some restrictions on using @extend inside media queries ... This means that if you use @extend in media queries, you can only extend the selectors that appear in the same block. For example, this code works fine:

    @media only screen and (max-width: 320px) and (orientation: portrait){
      .error {
        border: 1px #f00;
        background-color: #fdd;
      }
      .seriousError {
        @extend .error;
        border-width: 3px;
      }
    }
    

    This option is wrong:

    .error {
      border: 1px #f00;
      background-color: #fdd;
    }
    @media only screen and (max-width: 320px) and (orientation: portrait) {
      .seriousError {
        @extend .error;
        border-width: 3px;
      }
    }
    

    But we can do otherwise by using silent classes that do not fall into styles until we make them @extend.

    //silent class
    %big {
      width: 20px;
      height: 20px;
    }
    .block_1 {
      @extend %big;
    }
    .block_2 {
      @include respond-to('large'){
        @extend %big;
      }
    }
    .block_3 {
      @include respond-to('large'){
        @extend %big;
      }
    }
    

    Get the right compiled CSS:

    .block_1 {
      height: 20px;
      width: 20px;
    }
    @media screen and (min-width: 600px) {
      .block_2, .block_3 {
      height: 20px;
      width: 20px;
      }
    }
    

    In addition, everyone would like the compiled CSS to be smaller and the CSS of the individual request rules to be combined, for example:

    .profile-pic {
      @media screen and (max-width: 320px) {
        width: 100px;
        float: none;
      }
    }
    .biography {
      @media screen and (max-width: 320px) {
        font-size: 15px;
      }
    }
    

    I would like to receive:

    @media screen and (max-width: 320px) {
      .profile-pic {
        width: 100px;
        float: none;
      }
      .biography {
        font-size: 15px;
      }
    }
    

    Instead, we get:

    @media screen and (max-width: 320px) {
      .profile-pic {
        width: 100px;
        float: none;
      }
    }
    @media screen and (max-width: 320px) {
      .biography {
        font-size: 15px;
      }
    }
    

    When working with Rails 3.1+ and Sprockets, you can use the sprockets-media_query_combiner jam to make CSS rules combine optimally .
    There is also a good jam that can be used in the responder project , for more convenient use of media queries.

    Visitors viewing your site on tablets or phones will definitely thank you.

    Also popular now: