Less Mixins — Complete Guide
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
- Forgetting parentheses in mixin calls — .mixin-name (without parentheses) outputs a literal CSS rule. .mixin-name() calls the mixin.
- Using commas instead of semicolons in parameters — Use semicolons to separate parameters so commas can be used in values like box-shadow lists.
- Guards with wrong syntax — Guards use
when (@condition), not@if. This is a common confusion for Sass developers. - No default case in guards — If no guard matches, the mixin outputs nothing. Provide a default guard (without when) as fallback.
- Recursive mixin calls without base case — Mixins can call themselves recursively. Ensure there is a terminating guard.
- Not using @arguments for long parameter lists — @arguments is cleaner than listing all parameters individually for pass-through cases.
- Overloading mixins without clear organization — Too many pattern-matched overloads make mixins hard to understand.
Practice Questions
- How do you add a conditional guard to a Less mixin? Use
when (@condition)after the mixin name:.mixin() when (@condition) { }. - What does @arguments capture in a mixin? All arguments passed to the mixin as a single space-separated value.
- How does pattern matching work in Less? Less selects the mixin definition that matches the number and types of arguments provided.
- How do you separate mixin parameters to allow commas in values? Use semicolons as parameter separators.
FAQ
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