chavab_1
chavab_1

Reputation: 237

SASS Media Query Mixin

I'm trying to get my breakpoints setup following this tutorial. They are working correctly when I target just one property. When I try to create a query that targets two (width and height) it only displays the latter. I've researched the Sass functions that I'm using and it should be rendering correctly so I'm not sure what the problem is. I'm using sass-rails on Ruby on Rails version 4.2.2.

Thanx

$breakpoints: (
  'small'  : ( max-width:  20em ),
  'mobile' : ( min-width:  36.25em ),
  'tablet'  : ( min-width: 48em ),
  'desktop'  : ( min-width: 60em ),
  'wide'    : ( min-width: 75em ),
  'height'    : ( min-width: 75em ) and (min-height: 62.5em)  
);

@mixin media($name) {
  @if map-has-key($breakpoints, $name) {
    @media #{inspect(map-get($breakpoints, $name))} {
      @content;
    }
  }

  @else {
    @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
        + "Please make sure it is defined in `$breakpoints` map.";
  }
}

This is what is rendered:

@media (min-height: 62.5em) {

}

Upvotes: 2

Views: 3434

Answers (2)

Kyzer
Kyzer

Reputation: 568

This is what I use when wanting to target more then one media query (obviously set your queries to what ever you wish):

$size__site_content_width : 1024px;

/* Media Queries */
$media_queries : (
    'mobile'    : "only screen and (max-width: 667px)",
    'tablet'    : "only screen and (min-width: 668px) and (max-width: $size__site_content_width)",
    'desktop'   : "only screen and (min-width: ($size__site_content_width + 1))",
    'retina2'   : "only screen and (-webkit-min-device-pixel-ratio: 2) and (min-resolution: 192dpi)",
    'retina3'   : "only screen and (-webkit-min-device-pixel-ratio: 3) and (min-resolution: 288dpi)",
    'landscape' : "screen and (orientation:landscape) ",    
    'portrait'  : "screen and (orientation:portrait) "
);

@mixin for_breakpoint($breakpoints) {
    $conditions : ();
    @each $breakpoint in $breakpoints {
      // If the key exists in the map
      @if map-has-key($media_queries, $breakpoint) {
        $conditions: append(
            $conditions,
            #{inspect(map-get($media_queries, $breakpoint))},
            comma
        );
      }
      @else {
        @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
        + "Please make sure it is defined in `$breakpoints` map.";
      }
    }

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

}

And us it like this in my scss:

#masthead {
    background: white;
    border-bottom:1px solid #eee;
    height: 90px;
    padding: 0 20px;
    @include for_breakpoint(mobile desktop) {
        height:70px;
        position:fixed;
        width:100%;
        top:0;
    }
}

and that outputs this:

#masthead { 
  background: white;
  border-bottom: 1px solid #eee;
  height: 90px;
  padding: 0 20px;
}

@media only screen and (max-width: 667px), only screen and (min-width: 1025px) { 
  #masthead {
    height: 70px;
    position: fixed;
    width: 100%;
    top: 0;
  }
}

Upvotes: 0

Daisi
Daisi

Reputation: 2418

Normally when storing media queries in variables or as values in a key value pair, they should be stored as strings. Check out these sites Media Queries by David Walsh and Responsive Web Design in Sass by Mason Wendell

Replace this line of code
'height' : ( min-width: 75em ) and (min-height: 62.5em)
with
'height' : "( min-width: 75em ) and (min-height: 62.5em)"

Now that the values passed to the mixin can either be a string or list, the mixin needs to recognise these changes

@mixin media($name) {
  @if map-has-key($breakpoints, $name) {
    $value: map-get($breakpoints, $name);
    $query: if(type-of($value) == "string", $value, inspect($value));
    @media #{$query} {
      @content;
    }
  }
  @else {
    @warn "Unfortunately, no value could be retrieved from `#{$breakpoint}`. "
        + "Please make sure it is defined in `$breakpoints` map.";
  }
}

$breakpoints: (
  'small'  : ( max-width:  20em ),
  'wide'    : "( min-width: 75em ) and (min-height: 62.5em) and (max-height: 100em)",
  'height'    : "( min-width: 75em ) and (min-height: 62.5em)"  
);

div.gta {
  @include media(wide) { ... }
}

div#mgs {
  @include media(height) { ... }
}

This compiles to the following CSS

@media (min-width: 75em) and (min-height: 62.5em) and (max-height: 100em) {
  div.gta { ... }
}

@media (min-width: 75em) and (min-height: 62.5em) {
  div#mgs { ... }
}

This will allow the mixin to be used on any number of media queries

Upvotes: 4

Related Questions