Skip to content

Less Mixins — Complete Guide

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Less Mixins. We cover key concepts, practical examples, and best practices to help you master this topic.

Less mixins use class-like definitions with parametric options, guards for conditional output, and pattern matching for flexible reusable style blocks.

What You'll Learn

  • Defining and calling mixins
  • Parametric mixins with defaults
  • Mixin guards for conditions
  • Pattern matching with mixins
  • The @arguments variable
  • The @rest variable for variable arguments
  • Namespaced mixins

Why It Matters

  • Mixins are the primary abstraction in Less
  • Guards enable conditional compilation
  • Pattern matching chooses implementations based on arguments
  • Namespacing organizes related mixins

Real-World Use

  • A button mixin generates multiple variants
  • A responsive mixin with guards handles different breakpoints
  • A theming mixin uses pattern matching for modes
  • A library of utility mixins is namespaced
flowchart LR
  A[Less Mixins] --> B[Parametric]
  A --> C[Guards]
  A --> D[Pattern Matching]
  B --> E[.mixin(@param) { }]
  C --> F[.mixin() when (@condition) { }]
  D --> G[.mixin(@a, @b) { } / .mixin(@a) { }]

Mixin Patterns

Code Example: Basic and Parametric Mixins

// Basic mixin (no parameters)
.visually-hidden() {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
}

// Parametric mixin with defaults
.button-variant(@bg; @color: #fff; @hover-bg: darken(@bg, 10%)) {
    background: @bg;
    color: @color;
    border: none;
    border-radius: 4px;
    padding: 8px 16px;
    font-size: 1rem;
    cursor: pointer;
    min-height: 44px;

    &:hover {
        background: @hover-bg;
    }

    &:focus-visible {
        outline: 3px solid fade(@bg, 40%);
        outline-offset: 2px;
    }
}

// Usage
.btn-primary {
    .button-variant(#0066CC);
}

.btn-secondary {
    .button-variant(#6c757d);
}

.btn-custom {
    .button-variant(#ff6600; #fff; #cc5200);
}

// Using semicolons to separate parameters (allows commas in values)
.box-shadow(@shadows) {
    box-shadow: @shadows;
}

.element {
    .box-shadow(0 2px 4px rgba(0,0,0,0.1), 0 4px 8px rgba(0,0,0,0.05));
}

Expected output: Mixins use class-like syntax with parentheses. Parameters are separated by semicolons (so commas can be used in values). Default parameter values make mixins flexible.

Code Example: Mixin Guards

// Guards: conditional mixin inclusion
// Syntax: .mixin() when (@condition) { ... }

// Responsive mixin with guards
.respond-to(@bp) when (@bp = sm) {
    @media (min-width: 480px) { @content; }
}
.respond-to(@bp) when (@bp = md) {
    @media (min-width: 768px) { @content; }
}
.respond-to(@bp) when (@bp = lg) {
    @media (min-width: 1024px) { @content; }
}

// Note: Less does not have @content.
// Use a different pattern: wrap styles in a class.

// Guard for button size
.button-size(@size) when (@size = small) {
    padding: 4px 8px;
    font-size: 0.75rem;
}

.button-size(@size) when (@size = medium) {
    padding: 8px 16px;
    font-size: 1rem;
}

.button-size(@size) when (@size = large) {
    padding: 12px 24px;
    font-size: 1.25rem;
}

// Guard with comparison
.font-size(@size) when (@size >= 1.5rem) {
    line-height: 1.2;
}
.font-size(@size) when (@size < 1.5rem) {
    line-height: 1.6;
}

// Guard with boolean operators
.mixin(@a) when (isnumber(@a)) and (@a > 0) {
    // Only applies when @a is a positive number
    width: @a * 1px;
}

// Guard with or
.mixin(@a) when (@a = 'dark'), (@a = 'night') {
    background: #1a1a2e;
    color: #e0e0e0;
}

// Guard for color type validation
.text-color(@bg) when (lightness(@bg) >= 50%) {
    color: #333;
}
.text-color(@bg) when (lightness(@bg) < 50%) {
    color: #fff;
}

Expected output: Guards use when keyword with conditions. Multiple definitions of the same mixin with different guards are tried in order. The first matching guard applies.

Code Example: Pattern Matching

// Pattern matching: different implementations based on argument structure

// Pattern: single value
.margin(@all) {
    margin: @all;
}

// Pattern: two values
.margin(@vertical, @horizontal) {
    margin: @vertical @horizontal;
}

// Pattern: three values
.margin(@top, @horizontal, @bottom) {
    margin: @top @horizontal @bottom;
}

// Pattern: four values
.margin(@top, @right, @bottom, @left) {
    margin: @top @right @bottom @left;
}

// Usage: Less chooses the matching pattern
.element-1 { .margin(16px); }               // Single value
.element-2 { .margin(16px, 32px); }         // Two values
.element-3 { .margin(16px, 32px, 8px); }    // Three values
.element-4 { .margin(16px, 32px, 8px, 4px); } // Four values

// Pattern: specific values
.padding(@value) when (@value = none) {
    padding: 0;
}
.padding(@value) when (isnumber(@value)) {
    padding: @value;
}

.element { .padding(16px); }  // Calls number version
.element2 { .padding(none); } // Calls none version

Expected output: Less matches mixin calls to definitions by argument count and guards. This enables overloaded functions similar to other programming languages.

Code Example: @arguments and @rest

// @arguments: captures all parameters as a single variable
.box-shadow(@x, @y, @blur, @spread, @color) {
    box-shadow: @arguments;
    // Equivalent to: @x @y @blur @spread @color
}

.element {
    .box-shadow(0, 2px, 4px, 0, rgba(0,0,0,0.1));
}

// @rest: captures remaining arguments (variable arguments)
.transition(@property; @rest...) {
    transition: @property @rest;
}

.element {
    .transition(opacity; 0.3s ease);  // transition: opacity 0.3s ease;
    .transition(all; 0.2s ease-in-out); // transition: all 0.2s ease-in-out;
}

// @rest with multiple properties
.gradient(@direction; @colors...) {
    background: linear-gradient(@direction, @colors);
}

.element {
    .-gradient(to bottom; #0066CC, #0052a3, #003d80);
}

Expected output: @arguments captures all parameters as a space-separated list. @rest captures any remaining arguments after the named parameters, enabling variable-length argument lists.

Common Mistakes

  1. Forgetting parentheses in mixin calls — .mixin-name (without parentheses) outputs a literal CSS rule. .mixin-name() calls the mixin.
  2. Using commas instead of semicolons in parameters — Use semicolons to separate parameters so commas can be used in values like box-shadow lists.
  3. Guards with wrong syntax — Guards use when (@condition), not @if. This is a common confusion for Sass developers.
  4. No default case in guards — If no guard matches, the mixin outputs nothing. Provide a default guard (without when) as fallback.
  5. Recursive mixin calls without base case — Mixins can call themselves recursively. Ensure there is a terminating guard.
  6. Not using @arguments for long parameter lists — @arguments is cleaner than listing all parameters individually for pass-through cases.
  7. Overloading mixins without clear organization — Too many pattern-matched overloads make mixins hard to understand.

Practice Questions

  1. How do you add a conditional guard to a Less mixin? Use when (@condition) after the mixin name: .mixin() when (@condition) { }.
  2. What does @arguments capture in a mixin? All arguments passed to the mixin as a single space-separated value.
  3. How does pattern matching work in Less? Less selects the mixin definition that matches the number and types of arguments provided.
  4. How do you separate mixin parameters to allow commas in values? Use semicolons as parameter separators.

FAQ

Does Less have @content blocks like Sass?

No. Less does not support @content. Use wrapper mixins or pass styles as mixin arguments instead.

Can I use guard conditions with variable types?

Yes. Less supports type-checking functions: isnumber(), iscolor(), isstring(), isurl(), ispixel(), ispercentage(), isem().

How do I create a mixin library?

Define mixins in a separate file and @import them. Use namespacing (e.g., #utils > .center()) to organize.

Mini Project

Create a comprehensive Less mixin library with 10 mixins: (1) .button-variant with param defaults, (2) .respond-to with guards for 4 breakpoints, (3) .text-color that returns readable text based on background lightness using guards, (4) .margin and .padding with pattern matching for 1-4 values, (5) .box-shadow using @arguments, (6) .transition using @rest for variable properties, (7) .visually-hidden for Accessibility, (8) .truncate for text overflow, (9) .aspect-ratio for responsive embeds, (10) .focus-ring for accessible focus. Create a sample page that uses all mixins. Compare the output file size to hand-written CSS.

What's Next

Continue with Lesson 22: Less Nesting and Scope for advanced nesting in Less.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro