LESS#
Less (“Leaner Style Sheets”) is a CSS preprocessor with variables, nesting, mixins, and functions. The syntax stays a strict superset of CSS (any valid CSS is valid Less), and the result compiles to plain CSS.
Released in 2009 by Alexis Sellier; written in JavaScript and runs in Node, the browser, or via build-tool plugins. Bootstrap 3 was its most visible early adopter.
In 2026 Less is less common than SCSS in greenfield projects but still ubiquitous in long-lived codebases (notably Bootstrap 3 / 4 derivatives and many enterprise UI libraries).
Setup#
The minimum to compile Less. Install less, point lessc
at a source file, optionally enable source maps for in-
browser debugging. Most build tooling (Vite, Webpack, Rspack,
Parcel) handles compilation automatically once the package is
installed.
$ npm install -g less
$ lessc styles.less styles.css
$ lessc styles.less styles.min.css --clean-css
$ lessc --source-map styles.less styles.css
$ npx nodemon -e less -x 'lessc styles.less styles.css'
Most build tools (Vite, Webpack, Rspack, Parcel) compile .less
natively when less is installed.
Variables#
Less variables use the @ prefix, the syntactic
distinction from SCSS’s $. Compile-time only, so the
output CSS has literal values; reach for CSS custom
properties (--var) when you need runtime theming or
JavaScript-driven changes.
@color-bg: #fff;
@color-fg: #111;
@space-base: 1rem;
@radius-md: 8px;
.card {
background: @color-bg;
padding: @space-base * 1.5;
border-radius: @radius-md;
}
Like SCSS, Less variables are compile-time; the CSS output has
the literal values. Use CSS custom properties (--var) for
runtime theming.
Nesting#
Same authoring affordance as SCSS: group related rules
together; the compiler flattens them into normal CSS. &
is the parent selector. Native CSS nesting now exists, so
Less nesting is no longer the only way to get this in 2026.
.card {
padding: 1rem;
&.is-featured {
border: 2px solid @accent;
}
.title {
font-weight: 600;
}
&:hover .title {
color: @accent;
}
}
&is the parent selector; same as SCSS.Native CSS nesting now exists; Less nesting compiles to similar output.
Mixins#
In Less, any class is also a mixin; you can include a class’s declarations inside another rule. The implicit-mixin behavior is the most distinctive Less feature compared to SCSS, and the source of both its convenience and its occasional surprises.
.card {
padding: 1rem;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,.1);
}
.product { .card; }
.modal { .card; padding: 2rem; }
Parameterized mixins.
.border-radius(@r: 8px) {
border-radius: @r;
}
.button { .border-radius(); }
.modal { .border-radius(16px); }
If you want a mixin not to appear in compiled output as its own
rule, prefix it with . and append parentheses:
.helper() { // not emitted as a rule
padding: 1rem;
}
.card { .helper(); } // emitted as .card { padding: 1rem }
Functions#
Built-in functions for color manipulation, math, units, and strings. Less ships with a comprehensive standard library; the categories below cover the bulk of what authors reach for in real stylesheets.
@accent: #0b3d91;
.button {
background: @accent;
border-color: darken(@accent, 10%);
padding: ceil(@space-base * 1.5);
}
.alt-button {
background: lighten(@accent, 20%);
color: contrast(@accent, white, black);
}
Common categories.
Color,
darken,lighten,saturate,desaturate,mix,contrast,fade,hsl.Math,
ceil,floor,round,percentage,sqrt,mod,pow.String,
e()(escape),%(...)(string format),replace.List / map,
length,extract.
Imports#
How Less assembles multi-file stylesheets. Less’s @import
is more configurable than SCSS’s: you can import a file’s
declarations only as references ((reference)), inline its
text without parsing, or force a .css extension to be
processed as Less.
@import "tokens.less";
@import (reference) "mixins.less"; // include but don't output rules
@import (less) "vendor.css"; // process as Less even with .css ext
@import (once) "tokens"; // (default: imports happen only once)
Useful options.
(reference), definitions only; nothing emitted unless used.(inline), include verbatim without parsing.(less)/(css), force how a file is treated.(once)/(multiple).
Loops and Conditionals#
Less doesn’t have explicit loops or if/else. The idiom
is recursion plus guards (when ...), which works but
gets awkward fast for nontrivial logic. SCSS’s @each and
@for are more readable for the same patterns:
.columns(@n; @i: 1) when (@i =< @n) {
.col-@{i} { width: percentage(@i / @n); }
.columns(@n; @i + 1);
}
.columns(5);
Guards (when ...) replace if/else:
.text(@light) when (luma(@light) > 50%) {
color: black;
}
.text(@dark) when (luma(@dark) <= 50%) {
color: white;
}
Maps (Less Maps)#
Modern Less (3+) supports map-style lookup, addressing one of the longest-standing complaints about the language. Maps are the Less equivalent of SCSS’s design-token storage – key-value pairs that drive utility-class generation.
@sizes: {
sm: 0.875rem;
md: 1rem;
lg: 1.25rem;
};
.text-sm { font-size: @sizes[sm]; }
.text-md { font-size: @sizes[md]; }
& Tricks#
Beyond simple parent referencing, & is the building block
for BEM-style block/element/modifier naming and suffix-based
composition. The patterns below let you write the rules in
the structure of the component while emitting flat,
specificity-cheap CSS.
.card {
&__header { padding: 1rem; }
&__body { padding: 1rem; }
&--large { padding: 2rem; }
// Combinator
& + & {
margin-top: 1rem;
}
}
Less vs. SCSS#
A side-by-side comparison of the two main CSS preprocessors. Both have feature parity for the day-to-day cases (variables, nesting, mixins, color functions); SCSS edges ahead on module composition and looping power, while Less remains the incumbent in long-lived Bootstrap 3 / AntD-derived codebases.
Aspect |
Less SCSS |
|---|---|
Variable sigil |
|
Implementation |
JavaScript (Node) Dart (originally Ruby) |
Mixins |
|
Conditionals |
|
Loops |
recursion |
Modules |
|
Maps |
map literals full map type with helpers |
String escape |
|
Speed |
fast (JS in build) very fast (Dart Sass) |
Adoption |
declining; Bootstrap 3-4 dominant in CSS-preprocessor space |
Compatible-feeling, mutually exclusive in any one project. Tooling has parity for the common cases (variables, nesting, mixins, basic functions); SCSS edges ahead in module composition and looping power.
Less versus plain CSS#
The case for and against Less in 2026, given that native CSS has caught up on most preprocessor features. Less is mostly inherited rather than chosen these days; the case for is inheritance, the case against is “native CSS does this now”:
You inherit a Less codebase (Bootstrap 3, AntD legacy, internal Less-based design systems).
You prefer
@variablesyntax and “any class is a mixin” ergonomics.You want a JS-implementation that runs in the browser at dev time.
The case against in greenfield work.
Native CSS nesting handles the
&use case.CSS custom properties cover most variable use cases at runtime.
color-mixandoklchcoverdarken/lightennatively.Native cascade layers replace many import-order tricks.
AntD and Less#
Ant Design was the most-cited modern adopter; its theming relied heavily on Less variables. AntD 5+ moved to a CSS-in-JS approach (CSSinJS via cssinjs.org), but many existing AntD-based apps still ship Less builds and will for years yet.
Bootstrap and Less#
Bootstrap’s preprocessor history is a useful timeline of CSS authoring shifts. Bootstrap 3’s Less-based theming was Less’s biggest visibility moment; the migration to SCSS in Bootstrap 4 mirrored the broader industry move.
Bootstrap 3 (2013), Less-based.
Bootstrap 4, migrated to SCSS.
Bootstrap 5, still SCSS plus utility-first additions.
Many enterprise themes were built on Bootstrap 3 and remain in Less.
Pitfalls#
JavaScript-implementation differences, Less in the browser versus Less compiled at build time can produce slightly different results; pin to a build-time compile.
Parent selector ``&``, subtle differences from SCSS (especially in compound selectors).
Variable scope, Less variables are lazy; the last definition in scope wins regardless of source order. Surprises if you expect declaration order to matter.
Mixins emit rules unless ``()`` suffix, a class definition used as a mixin still appears in the compiled output by default.
``@import`` versus CSS ``@import``, Less may inline by default; use
(css)to keep a runtime CSS import.