How to structure media queries in Sass
How to create consistent, reusable, self-contained and responsive modules.
Practically every site now is built with at least a nod to responsive web design. The way we structure these responsive styles has a direct relation to how complex the project will be to maintain and edit in the future as updates are made and the project grows in size.
Despite this, it seems as though a widely accepted approach for how and where to structure these responsive styles is yet to be adopted consistently by developers. Although nowhere near as bad as 'the old days' of CSS, before preprocessors and naming methodologies, this is causing an inconsistent and often messy approach to structuring the responsive styles for elements.
Just getting started with your site? Pick a top website builder and web hosting service. Working with a large team? Make sure your cloud storage keeps everyone up to date with your design system.
CSS in the past
To understand the problem we're facing, let's go back to the beginning. One of the reasons that CSS preprocessors such as Sass or LESS were created in the first place is because CSS can get extremely messy and is famously hard to maintain. We used to find that after a while, even small websites had lines upon lines of CSS styles that were left in place just because the developer was unsure if it was required or the remnants of a removed feature or outdated element that could be deleted.
Take the following scenario as an example:
.heading { background: #000000; };
.title { font-size: 16px; };
.title_small { font-size: 14px; }
.title_alt { font-family: sans-serif; }
Although you may think that it is safe to assume the .title element is the title for the .heading element in this context, in fact you can't actually be completely sure that it is not used to style any other title element in the site. Also, where is .title_alt class used and is it still required or in use? You can see how even with such a simple example it can become a time-consuming exercise to check all of this before making changes.
Because of this, lots of developers would save time by adding a new class to the element or using a more complex CSS selector to make the changes they desired, which then in turn increased the complexity of the CSS for the next time a change was needed.
Get top Black Friday deals sent straight to your inbox: Sign up now!
We curate the best offers on creative kit and give our expert recommendations to save you time this Black Friday. Upgrade your setup for less with Creative Bloq.
Preprocessors, naming conventions and Modular CSS
Thanks to the ability to nest styles, use variables, extend other classes and more, preprocessors revolutionised the way that we create and maintain CSS. Unfortunately they don't fully solve the problem of messy, outdated styles that spread and grow throughout a project as it ages like an infection.
Along came naming conventions and CSS methodologies such as BEM, which when applied give a much greater level of context to styles.
When combined with making variations, modifications and the styles of nested elements self-contained by using CSS Modules, a really strong way to structure your styles was born.
Below you can see how these improvements can solve the problems we encountered with our earlier code example:
.heading {
background: $black;
}
.heading__title {
font-size: 16px;
&.heading__title--small {
font-size: 14px;
}
}
.post__title--alt {
font-family: sans-serif;
}
It is instantly clear that the title styles here are specifically contained within the heading element. You can safely remove/edit these without worry of affecting other elements. You can also see that the small title was a variation of the header title, but that the alt title style was for another element.
In my opinion, when following this combination of structure and naming methodology, it is fairly easy to create clean, easily maintainable CSS styles. Context can quickly be gained and self-contained modules of CSS can be copied and pasted in other projects, or amended and removed with ease.
It may seem as though the problem of messy and unmaintainable code was resolved. But as responsive design became more and more relevant, it became apparent that we were repeating many of our mistakes over again and generating badly structured, overly complex approaches to creating responsive websites.
Solving this problem is where media query bubbling comes into play.
Responsive style locations
Thanks to the mentioned improvements in our approach to creating CSS, whenever I inherit or collaborate on a project these days, I rarely experience the dread or concern that I was opening myself up to fall into a fire of specificity hell or structural disorganisation that I used to have in those situations. I now know that I can quickly find and understand relevant classes and styles thanks to naming methodologies, and make my changes without unimaginable consequences to other elements, thanks to Modular CSS.
Unfortunately one major cause of frustration I encounter is that responsive styles are still inconsistently located throughout the project. They may well be contained within a modular structure and named appropriately in a naming methodology, but project by project I see many different ways that developers choose to include their responsive styles.
Some create a separate Sass partial named _mobile.scss or _tablet.scss for example. Some place media queries at the bottom of the relevant file in ascending or descending order and others just place them randomly between styles for other elements. With this approach, I find myself tabbing between files and scrolling to the top and bottom of files just to gain a full understanding of one element's styles across different breakpoints.
Media query bubbling
As you can see, there are many problems with this that all combine to cause the developer to spend more time working on changes/amendments than is actually needed.
- It duplicates styles and makes the process of maintaining and finding all relevant styles for a component harder. You have to look in multiple locations or files to get a complete picture of an element's styles.
- The element is no longer self-contained. You cannot easily reuse it in another project or confidently delete/amend it without adverse affects or lingering code remaining.
- For each new project, time is wasted figuring out how that project approaches responsive styles.
- Switching between projects becomes harder because you have to switch between approaches in your head. This can lead to projects accidentally having a mix of approaches, which again leads to messy CSS.
The solution that I like to implement to fix this is called Media Query Bubbling. The simplest way to explain it is to consider media queries to be like any other variation of your modular element. The same as a BEM variation class of .heading__title is .heading__title—variation, for example. This means that the media query should be nested within, just like your modifying classes. See the following code as an example of this:
.header {
background: $black;
@media only screen and (min-width: 640px) {
background: $white;
}
}
In this example, you can clearly see in one location that the background for the header changes to white at 640px or higher. By self-containing the media query along with the element's styles, you have once again created a totally self-contained module that can be reused or edited with confidence. There is no need to cross-check a _mobile.scss file or search the project for other mentions of the class to be sure you have covered all breakpoints.
Nested media query bubbling
Again, I have seen many variations of how developers choose to structure the responsive styles of their elements. This should be considered no different than styling the parent element and all media queries and styles should be self-contained. See the following example:
.heading__title {
font-size: 16px;
@media only screen and (min-width: 640px) {
font-size: 18px;
}
&.heading__title--small {
font-size: 14px;
@media only screen and (min-width: 640px) {
font-size: 16px;
}
}
}
You can see that the font size for the heading__title gets bigger when the viewport is 640px or bigger and how the smaller variation of the heading title also enlarges but is defined to be smaller than standard. Using this technique, it is very important to apply the BEM methodology strongly to ensure you don't end up nesting several levels deep. For example, ensure that the .heading__title element is a self-contained CSS module that is not needlessly nested within the .heading element.
Cleaner responsive styles
By taking what we learned from the benefits provided by BEM and Modular CSS and applying it to media queries within the same structure, we stop ourselves from repeating the mistakes of our past.
By working with media queries in this way, you don't have to learn a totally new methodology or structure for your styles. We're basically taking the Modular CSS approach and applying it to our media queries, which should feel fairly natural.
We're also creating cleaner CSS with less duplication of CSS classes across files and saving development time by removing the need to check multiple locations when making amends.
This article was originally published in net, the magazine for professional web designers and developers. Subscribe to net here.
Related articles:
Thank you for reading 5 articles this month* Join now for unlimited access
Enjoy your first month for just £1 / $1 / €1
*Read 5 free articles per month without a subscription
Join now for unlimited access
Try first month for just £1 / $1 / €1