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

.name (any class) @mixin / @include

Conditionals

when (...) guards @if / @else

Loops

recursion @for / @each / @while

Modules

@import @use / @forward (modern)

Maps

map literals full map type with helpers

String escape

~"..." / e() #{...}

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 @variable syntax 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-mix and oklch cover darken / lighten natively.

  • 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.

See Also#

  • CSS, the underlying language.

  • SCSS, the dominant alternative preprocessor.