Using Parametric Mixins in Less for Flexible, Reusable CSS
Learn how Less parametric mixins—using defaults, pattern matching, and guards—let you generate reusable, theme‑aware CSS without duplication.
14 Dec 2025, 08:11 UTC

The problem: repetitive style blocks
When building a UI component you often need the same set of declarations with small variations — different padding, a color that changes with a theme, or a media query that only applies at certain breakpoints. Writing these variations by hand leads to duplicated CSS and makes future updates error‑prone.
Thesis: Less parametric mixins let you encode those variations once
By defining a mixin that accepts parameters, supplies default values, overloads by argument count, and uses guards, you can generate the exact CSS you need from a single reusable block. The compiler picks the correct variant based on how you call the mixin, keeping your source DRY while the output stays plain CSS.
How parametric mixins work in Less
Default values
A mixin can declare a default for any parameter:
@mixin button(@bg: #007bff; @padding: 0.5rem 1rem) {
background-color: @bg;
padding: @padding;
border: none;
color: #fff;
cursor: pointer;
}
Calling .button(); uses the defaults, while .button(#28a745); overrides only the background.
Pattern matching by arity
Less selects the first mixin whose signature matches the number of arguments passed. You can overload a name:
@mixin button(@bg) {
background-color: @bg;
}
@mixin button(@bg; @padding) {
background-color: @bg;
padding: @padding;
}
If you supply one argument, the first definition is chosen; two arguments trigger the second.
Guards for conditional logic
Guards (when) add a boolean test that must be true for the mixin to be considered:
@mixin button(@bg; @padding) when (@bg = #007bff) {
background-color: @bg;
padding: @padding;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
@mixin button(@bg; @padding) when (@bg != #007bff) {
background-color: @bg;
padding: @padding;
border: 2px solid @bg;
}
When the background is the default blue, a shadow is added; otherwise a border appears.
Worked example: a theme‑aware button
Suppose you want a button that adapts to a light or dark theme and optionally receives a custom padding. The following Less file demonstrates the three mechanisms together.
// variables.less
@theme-light: #fff;
@theme-dark: #111;
// mixins.less
@mixin button(@bg; @padding: 0.5rem 1rem) when (@bg = @theme-light) {
background-color: @bg;
color: #000;
padding: @padding;
}
@mixin button(@bg; @padding: 0.5rem 1rem) when (@bg = @theme-dark) {
background-color: @bg;
color: #fff;
padding: @padding;
}
@mixin button(@bg; @padding: 0.5rem 1rem) {
/* fallback for any other color */
background-color: @bg;
color: #fff;
padding: @padding;
}
// usage.less
@import "variables.less";
@import "mixins.less";
.light-btn { .button(@theme-light); }
.dark-btn { .button(@theme-dark); }
.custom-btn { .button(#ff5733, 0.75rem 1.5rem); }
Compile with lessc -x usage.less output.css (using Less 4.2.0). The generated CSS will contain three rule sets: one for the light theme, one for the dark theme, and one for the custom orange button with the specified padding. No duplicate property blocks appear in the source.
Trade‑off and limitation
While parametric mixins increase reuse, each overload adds a branch to the compiler’s decision tree. With many overloads or complex guards, compile time can grow noticeably, and the generated CSS does not reveal which guard triggered a particular rule — making debugging harder when the output does not match expectations. A practical mitigation is to keep the number of overloads low and to unit‑test the mixin by compiling a small test file and inspecting the result.
Actionable closing
Start by identifying a repeated style pattern in your project. Extract it into a mixin with a sensible default, add an overload only if you genuinely need a different argument count, and use guards for theme‑ or state‑based variations. Compile with a recent Less version (>=3.0) to avoid the older guard‑semicolon quirk, and verify the output with lessc -v and a manual diff of the generated CSS. This approach gives you the flexibility of a preprocessor without sacrificing the clarity of plain CSS.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.