Stylesheets for a website are often written from a single “ideal” state (usually mobile-first or desktop), which is then added to and adjusted with a series of @media
queries:
Typical @media Breakpoints
body { /* general rules */ }
h1, h2 { /* still more general rules */ }
@media all and (max-width: 960px) {
/* first breakpoint */
body { /* changes to selectors */ }
}
@media all and (max-width: 650px) {
/* second breakpoint */
body { /* more changes */ }
h1 { /* more changes to other selectors */ }
}
This approach congregates all breakpoint changes for the site into groups, usually at the end of your stylesheet. While helpful from an organizational point of view, this does have a few downsides:
- “Clumping” selectors leads to broader browser interventions. Once your CSS has a few media queries, there’s an understandable desire to avoid adding further technical debt. As a result, developers tend to shoehorn new changes into existing
@media
sets. This creates a few CSS “jump points” for a site where everything changes, rather than a considered, granular response to changing viewport width. - Harder to find selectors. A selector may be altered several times across several different media queries widely separated in the stylesheet, making them hard to track down during bug testing and maintenance.
Sass Nested Media Queries
Sass inverts this approach: rather than clumping changes together under a few @media
breakpoints, it can place media queries inside selectors. Like many other aspects of Sass explored in this series, nested media queries are easiest to practice with on CodePen, where a variation of the code below resides:
body {
line-height: 1.3;
margin: 2rem;
background: grey;
@media all and (max-width: 650px) {
line-height: 1.4;
margin: 1rem;
background: black;
}
}
In English: under desktop viewing conditions, set the line-height
of the body to 1.3, margin
on all sides to 2rem
, and the background to grey, and alter its horizontal and vertical padding. If the viewport is 650 pixels wide or less, change all of these properties to something more suitable for small screen devices.
This means that you can associate all the media queries for a particular element with the element itself, rather than spreading them across multiple points in your stylesheet:
body {
font-size: 1rem;
@media all and (max-width: 650px) {
font-size: 1.2rem;
}
@media all and (max-width: 420px) {
font-size: 1.4rem;
}
}
This is incredibly useful when writing long, complex stylesheets, and addresses all the concerns of the traditional approach detailed above. However, it does bring a few possible disadvantages of its own, the primary one being the creation of a more complex stylesheet peppered with @media queries. Surprisingly, this does not affect performance: writing lots of little element @media queries is not significantly slower than the same changes grouped into a few queries. Readability of the final stylesheet isn’t a factor, as your output CSS should be minified anyway (one of the reasons I maintain a .zip of the Sass for this site).
Using nested media queries allows you to write immediate responsive interventions on elements, rather than trying to remember the selectors, properties and values you need to change as you search for a particular breakpoint. Which leads directly to another Sass feature…
Named Media Queries
If you decide to embrace the Sass approach of nested media queries, it can create one other potential problem: remembering breakpoint values. Thankfully, we can use Sass itself to solve that using variables:
$screen-large: 1500px;
$screen-med: 750px;
$screen-small: 420px;
@media (max-width: $screen-large) {
//
}
These named breakpoints are much easier to remember (and a good editor will even prompt or auto-complete them as you type, once you create the variables), making for fewer errors and less time spent searching through code. Of course, these variables can also be used in nested media queries inside selectors, and manipulated with Sass arithmetic to produce values for min-width
and other variations.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/ojNJgZ