Building Responsive Designs with SCSS Media Queries

SCSS enhances media queries by allowing nesting, keeping styles organised alongside their base styles. It uses variables and mixins to eliminate redundancy, making responsive design more manageable and maintainable throughout the development process.

Media queries are how a website adapts to the device viewing it: a layout that stacks vertically on a phone, spreads into columns on a tablet, and fills the width on a desktop. Plain CSS handles this perfectly well, but it scatters your responsive rules across the stylesheet, far from the elements they affect, and forces you to retype the same breakpoint values over and over. SCSS does not change what a media query does. It changes how you organise them, letting you keep responsive styles next to the elements they belong to and define your breakpoints in one place.

What Changes with SCSS

A media query applies different CSS rules depending on the characteristics of the device, most commonly its width. In plain CSS, a media query is a top-level block, which means the rules for a button at desktop width live somewhere completely separate from the button’s base styles. SCSS lets you nest the media query directly inside the selector, keeping everything about that element together. On top of that, you can store breakpoints in variables and wrap repetitive query patterns in mixins, which removes the duplication that plain CSS media queries tend to accumulate.

The Basic Syntax

You can write a media query in SCSS exactly as you would in CSS, as a top-level block:

@media (min-width: 768px) {
.cta-button {
background-color: #2980b9;
}
}

This works, but it separates the button’s responsive style from its base style. The more SCSS-idiomatic approach is to nest the query inside the selector:

.cta-button {
background-color: #3498db;
@media (min-width: 768px) {
background-color: #2980b9;
}
}

The result is identical in the compiled CSS, but the source is far easier to read and maintain. Everything about .cta-button, including how it responds to wider screens, lives in one block. The button shows the default blue on narrow screens and switches to the darker blue once the viewport reaches 768 pixels. When you later need to adjust this button, you do not have to hunt through the stylesheet for a separate media query block.

Bringing in Variables and Mixins

Nesting solves the organisation problem. Variables and mixins solve the repetition problem.

Start by defining your breakpoints as variables so the same numbers are not scattered as magic values throughout the stylesheet:

$breakpoint-md: 768px;
$breakpoint-lg: 1024px;

Now every responsive rule can reference $breakpoint-md instead of the literal 768px. If your design system later shifts that breakpoint, you change one line and every query using it updates.

The bigger win comes from wrapping the media query pattern in a mixin. This is where the @content directive comes in, a special feature that lets a mixin accept a block of styles from the caller and drop it into the right place:

@mixin respond-to($breakpoint) {
@if $breakpoint == md {
@media (min-width: $breakpoint-md) {
@content;
}
} @else if $breakpoint == lg {
@media (min-width: $breakpoint-lg) {
@content;
}
}
}

The mixin takes a friendly name like md or lg, matches it to the right breakpoint variable, and wraps whatever styles you pass in inside the correct media query. You then use it like this:

.cta-button {
background-color: #3498db;
@include respond-to(md) {
background-color: #2980b9;
}
@include respond-to(lg) {
padding: 15px 30px;
}
}

Everything between the braces of the @include is handed to the mixin through @content and placed inside the appropriate @media block. The benefit is that you never write @media (min-width: ...) by hand again. You write respond-to(md), which reads almost like plain English, and the mixin handles the mechanics. If you decide to change how a breakpoint works, you change the mixin once and every call follows.

A Few Guidelines

Keep your breakpoints in variables. This is the single most effective habit for responsive SCSS, because it gives you one source of truth for the values your entire layout depends on.

Nest media queries inside the selectors they affect. The whole point of SCSS media queries is keeping responsive styles next to base styles, so take advantage of it rather than reverting to scattered top-level blocks.

Build a mixin for your common query patterns. A respond-to mixin like the one above pays for itself quickly, both in reduced typing and in consistency across the project. Every developer reaching for the same named breakpoints means the responsive behaviour stays coherent.

Comment and group your media queries where they get dense. Even with good nesting, a complex component can accumulate several breakpoint rules, and a short note about what each one is doing saves the next reader some effort.

Test on real devices and a range of screen sizes. The compiled CSS is only correct if it actually behaves the way you intended in the browser, and emulators do not always catch everything that a real phone or tablet will.

The Takeaway

SCSS does not reinvent media queries, it makes them manageable. Nesting keeps each element’s responsive styles next to its base styles instead of in a distant block. Breakpoint variables give you one place to define and adjust the screen sizes your design responds to. And a mixin built around the @content directive lets you replace verbose, repeated @mediadeclarations with a single readable call. Together these turn responsive design from a sprawl of disconnected query blocks into something organised, consistent, and easy to change as your layout evolves.

See you soon

View Comments (2)

Leave a Reply

Prev Next

Subscribe to My Newsletter

Subscribe to my email newsletter to get the latest posts delivered right to your email. Pure inspiration, zero spam.

Discover more from Datalad - Data Science and ML

Subscribe now to keep reading and get access to the full archive.

Continue reading