LESS Beautifier

Formatting LESS is harder than formatting CSS because the syntax carries variables, mixin calls, guards and parent selectors that a plain CSS formatter mangles. Paste your source here, set the indent, and get readable code plus a readout of how deep the nesting actually goes.

LESS formatting bench

Indent
Brace

Press Ctrl + S to format without reaching for the mouse. Your code stays in the page and is never sent anywhere.

A CSS formatter breaks LESS. That is why this page exists.

Point a plain CSS beautifier at a LESS file and it will do something reasonable to the parts it recognises, then quietly damage the parts it does not. Semicolons separating mixin arguments get treated as statement ends. A colon inside @media (min-width: 48em) gets read as a property. Escaped strings written as ~"..." get reindented from the inside. The formatter on this page walks the source with the preprocessor syntax in mind, so those constructs survive the round trip.

Formatting is only half of what happens when you press Format. The panel above also reports what the file contains: how many variables it declares, how many mixins it defines against how many it calls, whether guards are in play, and the deepest point the nesting reaches. Those numbers say more about whether a stylesheet is going to be pleasant to maintain than the indentation ever will.

Pasted in
@brand:#1d365d;.rounded(@r:6px){border-radius:@r}
.card{background:#fff;.rounded();.title{color:@brand;&:hover{color:lighten(@brand,15%)}}}
Formatted out
@brand: #1d365d;.rounded(@r: 6px) {border-radius: @r;}
.card {background: #fff;.rounded();.title {color: @brand;&:hover {color: lighten(@brand, 15%);}}}

The at sign does two jobs, and that is where formatters slip

In CSS, @ starts an at-rule. In LESS it also starts a variable. The two look identical to a naive tokenizer, so a CSS formatter treats @primary: #1d365d; as a malformed at-rule and either indents it wrong or drops the space after the colon. The parser here decides what a colon means by looking ahead: if a semicolon or a closing brace arrives before an opening brace, it is a declaration and gets a space after the colon. If an opening brace arrives first, it is part of a selector and stays tight.

That single rule is what keeps a:hover from becoming a: hover while still turning color:red into color: red. It also handles the awkward middle case correctly, since @detached: { color: red; }; is a variable holding a ruleset and needs the brace left alone.

Nesting depth is the number worth watching

Nesting is the feature people reach for first and regret last. Each level you open concatenates into the selector the compiler emits, and the result stops being something you would ever write by hand. Four levels of source nesting produce a selector nobody can override without a fight.

Source depthCompiled selectorVerdict
1.cardFine
2.card .titleFine
3.card .title .badgeGetting long, still readable
4.card .body .list .itemFragile, tied to markup shape
5 or more.page .card .body .list .item aRewrite it as a flat class

The depth counter in the panel reports the deepest point in whatever you pasted, not an average. One runaway block in a 900 line file is enough to push it to 6, which is the point of showing the maximum rather than smoothing it out. The & parent selector does not add a level, so &:hover and &.is-active are free.

Mixin definitions, mixin calls, and the parentheses that decide what ships

LESS lets you write a mixin two ways, and the difference has nothing to do with style. A ruleset declared with empty parentheses is callable and produces no CSS of its own. The same ruleset declared without them is callable and compiled into the output, whether or not anything calls it.

.helper() { color: #333; }
.helper { color: #333; }

The first line adds nothing to your stylesheet until something calls .helper();. The second ships .helper{color:#333} to every visitor forever. That is how a build ends up with dozens of orphan utility classes nobody wrote on purpose. The report counts definitions and calls separately, and flags any call written as .helper; without the parentheses, since that shorthand is the usual sign the definition is missing them too.

Argument separators are the other trap. A mixin whose arguments contain commas has to use semicolons between them, which is exactly the character a CSS formatter treats as end of statement:

.shadow(0 1px 2px rgba(0,0,0,.2); inset 0 0 0 1px #eee);

The tokenizer tracks parenthesis depth, so semicolons and commas inside an argument list never trigger a line break. Only the ones at depth zero do.

Guards read like conditions, but they behave like pattern matching

A guard attaches a when clause to a mixin and decides whether that mixin applies. It looks like an if statement and is closer to overload resolution, since every matching definition runs, not only the first.

.label(@c) when (iscolor(@c)) {color: @c;}
.label(@c) when (default()) {color: #333;}

Both definitions carry the same name and arity. LESS evaluates each guard and applies all of the ones that pass, with default() acting as the fallback that only fires when no other guard matched. Miss that and you get two colors in the compiled rule, with the last one winning silently. The formatter keeps the guard on the same line as the selector, since splitting it makes the pair harder to compare at a glance.

Three things the formatter refuses to touch

Where this page stops

Questions people ask about formatting LESS

Syntax the formatter handles, syntax it leaves alone, and what the readout numbers mean.

Why not just use a CSS beautifier on my LESS file?

Because several pieces of LESS syntax look like broken CSS to a CSS parser. Variable declarations start with the same at sign as at-rules. Mixin arguments are separated by semicolons that a CSS formatter reads as the end of a statement. Escaped strings written with a tilde contain content that is not CSS at all. You often get output that still compiles, but the spacing around those constructs comes out wrong and you end up fixing it by hand.

What counts as a nesting level in the depth readout?

Every opening brace that sits inside another block adds one. A top level rule is depth 1, a rule nested inside it is depth 2, and so on. The ampersand parent selector does not add a level, so writing a hover state as an ampersand followed by colon hover keeps the depth where it was. The number shown is the deepest single point in the file rather than an average across it.

The report flagged a mixin call written without parentheses. Why does that matter?

Calling a mixin as .helper instead of .helper() works, and on its own it is harmless. The reason it gets flagged is that the shorthand almost always travels with a definition that also lacks parentheses, and a definition without them is compiled into the output as a real CSS class on top of being callable. Add empty parentheses to any ruleset that exists only to be mixed into others, then the call site can keep them too.

Will this compile my LESS into CSS?

No. Formatting and compiling are separate jobs and this page only does the first. Your variables stay as variables and your mixin calls stay as calls. Send the file to the LESS to CSS converter when you want the compiled result, and use this page before committing the source.

Does anything I paste get uploaded?

No. The parser is JavaScript running in the page, and the only network request involved is loading the editor library itself. Once the page is open you can disconnect and every button still works. Nothing is stored between visits, so closing the tab clears what you pasted.

Why did my carefully placed blank lines disappear?

The formatter rebuilds the whitespace from scratch rather than adjusting what was there. Blank lines inside a block are dropped. The separation between top level rules is added back when the checkbox is on. If grouping declarations with blank lines matters to your team, treat this page as a fixer for badly formatted code rather than a formatter to run on every save.

Can it handle files that use both LESS and plain CSS?

Yes. Plain CSS is valid LESS, so a file mixing the two formats normally. At-rules including media queries, supports blocks, keyframes and font face are handled as ordinary blocks and get indented like any other. The one thing worth checking afterwards is any hand written vendor hack, since those sometimes rely on spacing that no formatter preserves.

What indent should I pick for a LESS project?

Two spaces is the common choice in preprocessor codebases, mostly because nesting eats horizontal room quickly and four spaces pushes deep rules off the screen. Tabs are worth choosing when your team already enforces them through an editorconfig file. The setting here only changes the output, so match whatever the repository already uses instead of introducing a third style.

My output looks far more nested than my input. What happened?

Almost always a missing closing brace. The formatter has no validation step, so an unclosed block means every rule after it is treated as nested inside it and the indentation keeps climbing. Look at the point where the runaway indentation begins and the unclosed block will be just above it.