Skip to content

LESS Guards in Practice

The mixin guards lesson introduced the when syntax. This lesson focuses on applying guards to real problems: building responsive helper mixins, switching between themes, and defensively validating mixin arguments.

Guards as LESS's Conditional Logic

Since LESS has no @if/@else statement, guards are the only mechanism for conditional logic. Understanding how to structure a family of guarded mixin definitions is essential for writing anything beyond the simplest static styles.

A well-designed guarded mixin family reads almost like a switch statement: each guarded definition handles one case, and an optional unguarded definition acts as a shared or fallback behavior.

.respond(@bp) when (@bp = mobile) {
  @media (max-width: 767px) { @content(); }
}
.respond(@bp) when (@bp = desktop) {
  @media (min-width: 768px) { @content(); }
}

This pattern is expanded fully in the Responsive Mixins lesson later in this course.

Structuring a Guarded Mixin Family

.mixin(@case) when (@case = A) { /* case A */ }
.mixin(@case) when (@case = B) { /* case B */ }
.mixin(@case) when (default())  { /* fallback */ }
  • List the most specific guarded cases first for readability, though evaluation order doesn't affect which guards match.
  • Use default() (covered in its own upcoming lesson) to define an explicit fallback case.
  • Combine iscolor(), isnumber(), and similar type checks with value comparisons for defensive mixins.
  • Keep each guarded case focused on exactly one condition for readability.

Practical Guard Patterns Cheatsheet

Common real-world guard patterns used across production LESS codebases.

Use Case Pattern Notes
Theme switch when (@theme = dark) Branches styles by a theme variable
Breakpoint switch when (@bp = mobile) Branches by a named breakpoint
Type validation when (iscolor(@c)) Only applies if argument is a color
Range validation when (@n > 0) and (@n =< 12) Restricts a numeric argument's valid range
Fallback case when (default()) Runs only if no other guard matched

Defensive Argument Validation with Guards

Guards can validate that a mixin received a sensible argument before applying styles, preventing a mixin from silently producing broken CSS when called with an unexpected value.

.grid-column(@n) when (@n > 0) and (@n =< 12) {
  width: percentage(@n / 12);
}
.grid-column(@n) when (@n =< 0), (@n > 12) {
  width: 0; // explicit fallback for an out-of-range argument
}

Theme Switching with Guards

A single mixin, gated by guards on a shared theme variable, can produce the correct styles for multiple themes from one call site, which is expanded on further in the Theme System lesson.

@theme: light;

.surface() when (@theme = light) {
  background: white;
  color: #111;
}
.surface() when (@theme = dark) {
  background: #111;
  color: white;
}

Keeping Guarded Mixin Families Readable

As a guarded mixin family grows, readability becomes important. Grouping all definitions of the same mixin name together, in the same file and in a logical order, keeps the overall conditional logic easy to follow.

  • Keep all guarded definitions of the same mixin name adjacent in the source file.
  • Add a short comment above the group explaining the overall branching logic.
  • Prefer 2-4 well-named guard cases over a dozen narrow, overlapping conditions.

Common Mistakes

  • Scattering guarded definitions of the same mixin name across multiple files, making the overall logic hard to trace.
  • Writing guard conditions so narrow and overlapping that debugging which one actually applied becomes difficult.
  • Forgetting a fallback case for arguments outside the guarded ranges, silently producing no styles at all.
  • Overusing guards for logic that would be clearer as separate, distinctly named mixins instead of one branching mixin.

Key Takeaways

  • Guards are LESS's only conditional mechanism, used in place of @if/@else.
  • A guarded mixin family reads like a switch statement: each case handles one condition.
  • Guards can defensively validate mixin arguments, preventing broken output from unexpected values.
  • Keep guarded definitions of the same mixin grouped together in source for readability.

Pro Tip

When a guarded mixin family grows past 3-4 cases, add a one-line comment above the group summarizing the branching logic; it saves the next developer from having to trace every guard condition manually.