Media queries in Sass

We can use media queries for targeting a block of CSS if a certain condition is true. We have a full range of media queries for specific characteristics at our disposal.

In this guide, we'll be looking at Bootstrap's approach to media queries using Sass and how to target specific screen sizes for our layouts.

Get the code:metal:


Maps

Maps represent an association between keys and values. This is handy to collect values into groups. Maps must be surrounded by parentheses and comma-separated. The !default flag won't allow value reassignment.

Breakpoints defined as a map from small to large.

$grid-breakpoints: ( xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, ) !default;

Maps are mostly manipulated by functions. map-get returns the value associated with the given key. If the map doesn't have such a key, it returns null.

map-get($map, $key);

Function Directives

First, we'll be creating some utility functions to later use them on our mixins to evaluate the condition we are targeting.

We can define our own functions in sass and use them in any value or script context. Functions can access any globally defined variables or accept arguments just like a mixin.

breakpoint-min <br> The breakpoint-min function uses map-get to return the minimum breakpoint width. Null for the smallest (first) breakpoint.

The $name argument defines the breakpoint size and $grid-breakpoints is a global variable used as the $breakpoints argument by default.

@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { $min: map-get($breakpoints, $name); @return if($min != 0, $min, null); }

breakpoint-next <br> The breakpoint-next uses map-keys($map) returns a list of all keys in a map and index returns the position of a pair in a map. The result is the name of the next breakpoint, or null for the last breakpoint.

@function breakpoint-next( $name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints) ) { $n: index($breakpoint-names, $name); @return if( $n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null ); }

breakpoint-max <br> breakpoint-max return the maximum breakpoint width. Null for the largest (last) breakpoint. The maximum value is calculated as the minimum of the next one less 0.02px to work around the limitations of min- and max- prefixes and viewports with fractional widths.

Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.
@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { $next: breakpoint-next($name, $breakpoints); @return if($next, breakpoint-min($next, $breakpoints) - 0.02px, null); }

Mixins

Mixins allow us define styles that can be re-used throughout our stylesheets. Let's define the breakpoint mixins for our media queries.

@mixin screen-up() { ... } @mixin screen-down() { ... } @mixin screen-only() { ... } @mixin screen-between() { ... }

When using the breakpoint mixin, we'll need to pass the breakpoint width or widths we are targeting. For Example:

@include screen-up(sm) { ... } @include screen-between(md, xl) { ... }

Bootstrap uses the mobile first approach. We don't need a query for the smallest breakpoint.

screen-up

This mixin targets @media of at least the minimum breakpoint width. It makes the @content apply to the given breakpoint and wider.

@mixin screen-up($name, $breakpoints: $grid-breakpoints) { $min: breakpoint-min($name, $breakpoints); @if $min { @media (min-width: $min) { @content; } } @else { @content; } }

screen-down

This mixin targets @media of at most the maximum breakpoint width. It makes the @content apply to the given breakpoint and narrower. There is no query for the largest breakpoint.

@mixin screen-down($name, $breakpoints: $grid-breakpoints) { $max: breakpoint-max($name, $breakpoints); @if $max { @media (max-width: $max) { @content; } } @else { @content; } }

screen-only

This mixin targets @media between the breakpoint's minimum and maximum widths. It makes the @content apply only to the given breakpoint, not viewports any wider or narrower.

@mixin screen-only($name, $breakpoints: $grid-breakpoints) { $min: breakpoint-min($name, $breakpoints); $max: breakpoint-max($name, $breakpoints); @if $min != null and $max != null { @media (min-width: $min) and (max-width: $max) { @content; } } @else if $max == null { @include screen-up($name, $breakpoints) { @content; } } @else if $min == null { @include screen-down($name, $breakpoints) { @content; } } }

screen-between

This mixin targets @media that spans multiple breakpoint widths. It makes the @content apply between the min and max breakpoints.

@mixin screen-between($lower, $upper, $breakpoints: $grid-breakpoints) { $min: breakpoint-min($lower, $breakpoints); $max: breakpoint-max($upper, $breakpoints); @if $min != null and $max != null { @media (min-width: $min) and (max-width: $max) { @content; } } @else if $max == null { @include screen-up($lower, $breakpoints) { @content; } } @else if $min == null { @include screen-down($upper, $breakpoints) { @content; } } }

How to use them

Media queries mixins:<br> screen-up, screen-down, screen-only, screen-between.

Target sizes:<br> xs, sm, md, lg, xl.

// example: apply to target (lg) and wider @include screen-up(lg) { .custom-class { color: red; } } // size range @include screen-between(md, xl) { ... }