Skip to content

LESS Responsive Mixins

Repeating the same @media (min-width: 768px) condition across dozens of components is fragile and hard to update. This lesson builds a reusable responsive mixin that wraps a breakpoint behind a simple, memorable name.

Why Wrap Media Queries in a Mixin?

A responsive mixin accepts a breakpoint name (or value) and, using guards, expands to the correct @media condition, letting every component reference .respond-above(tablet) instead of memorizing and repeating a raw pixel value.

This also means updating a single breakpoint value later, changing tablet from 768px to 800px, requires editing one variable instead of hunting through every component file for a matching raw number.

@bp-tablet: 768px;
@bp-desktop: 1024px;

.respond-above(@bp) when (@bp = tablet) {
  @media (min-width: @bp-tablet) { @content(); }
}
.respond-above(@bp) when (@bp = desktop) {
  @media (min-width: @bp-desktop) { @content(); }
}

.sidebar {
  width: 100%;
  .respond-above(tablet, { width: 260px; });
}

@content() (via a detached ruleset argument) inserts the caller-provided declarations inside the matched media query.

Responsive Mixin Pattern

.respond-above(@bp; @rules) when (@bp = name) {
  @media (min-width: value) { @rules(); }
}

.selector {
  .respond-above(name; { property: value; });
}
  • The second argument is a detached ruleset, a block of declarations passed in and later invoked with @rules();.
  • Guards branch on the named breakpoint to select the correct raw pixel value.
  • This pattern requires LESS's detached ruleset feature, supported since LESS 1.4.
  • Callers never need to know or repeat the raw breakpoint value directly.

Responsive Mixins Cheatsheet

Building blocks for a reusable breakpoint mixin system.

Piece Example Purpose
Breakpoint variables @bp-tablet: 768px; Single source of truth per breakpoint
Guarded mixin .respond-above(@bp) when (@bp = tablet) Maps a name to a media condition
Detached ruleset arg { width: 260px; } The declarations to run inside the query
Invoking the ruleset @rules(); Executes the passed-in declarations
Call site .respond-above(tablet, { ... }); Readable, name-based usage

Detached Rulesets, Briefly Explained

A detached ruleset is a block of CSS wrapped in curly braces and assigned to a variable (or passed as an argument), which can later be invoked like a mixin call using parentheses. It's the mechanism that lets a responsive mixin accept an arbitrary block of styles as an argument.

@my-rules: {
  color: red;
  font-weight: 700;
};

.box {
  @my-rules();
}

Adding respond-below() and respond-between()

A complete responsive mixin system usually needs more than just a min-width helper; max-width and range-based helpers cover the remaining common responsive scenarios.

.respond-below(@bp; @rules) when (@bp = tablet) {
  @media (max-width: (@bp-tablet - 1)) { @rules(); }
}

.respond-between(@from; @to; @rules) when (@from = tablet) and (@to = desktop) {
  @media (min-width: @bp-tablet) and (max-width: (@bp-desktop - 1)) { @rules(); }
}

Keeping a Growing Mixin Maintainable

As more named breakpoints are added, the guarded mixin definitions grow linearly, one guard per breakpoint name. This is a reasonable tradeoff for the readability gained at every call site.

  • Keep all breakpoint names and values defined in one shared variables file.
  • Add a short comment listing every supported breakpoint name above the mixin definitions.
  • Consider a map-like detached ruleset combined with each() if the number of breakpoints grows very large.

Common Mistakes

  • Hardcoding a raw pixel value directly at a component's call site instead of using the named responsive mixin.
  • Forgetting the semicolon after a detached ruleset variable assignment, which is required unlike a normal mixin definition.
  • Not adding a fallback or default() guard case for an unrecognized breakpoint name, silently producing no media query.
  • Building respond-below() without subtracting 1 from the next breakpoint's value, causing an overlapping range with respond-above().

Key Takeaways

  • A responsive mixin maps a memorable breakpoint name to its raw pixel value using guards.
  • Detached rulesets let the mixin accept an arbitrary block of declarations as an argument via @content-like invocation.
  • A complete system typically includes above, below, and between helpers for full responsive coverage.
  • Centralizing breakpoint names and values avoids repeated, hard-to-update raw pixel values across a project.

Pro Tip

Give your responsive mixins names that describe intent (respond-above, respond-below) rather than raw values (min-768), so a future change to the underlying breakpoint value never requires renaming call sites throughout your codebase.