LESS to CSS Converter

Type LESS on the left and read plain CSS on the right as you go. Variables, nesting, mixins, guards, and colour functions resolve in your browser, with the division rules of Less 3 and Less 4 both a click away.

Load a sample
LESS source0 lines0 B
Compiled CSS0 lines0 B
Paste LESS on the left and the compiled CSS lands here.

A stylesheet written against Less 3 compiles differently under Less 4, and the change is quiet. width: @grid / 3 produced 320px for years. Under Less 4 the same line ships @grid / 3 through to the CSS untouched, and the layout collapses with no error to point at. The Division control above switches between both rule sets so you see which one your source was written for.

What a compile pass actually does to your code

LESS is not a smaller language sitting on top of CSS. It is a text expander. Four things happen when you press Compile:

The counter under each pane tracks this. Load the Mixins sample and watch the byte count climb on the right. Output growing by 40 percent is normal, and it is the reason a minifier belongs at the end of a LESS build rather than the start.

Division: the one migration that breaks silently

Less 4 shipped with math: parens-division as the default. A slash outside parentheses is treated as a CSS separator, not an operator, because CSS itself uses slashes in font, grid-area, border-radius, and aspect-ratio.

Less 3 behaviour@grid: 960px;.col { width: @grid / 3; } .col { width: 320px; }
Less 4 default@grid: 960px;.col { width: @grid / 3; } .col { width: 960px / 3; }

Wrap the expression in parentheses and both modes agree: width: (@grid / 3) gives 320px everywhere. That is the fix worth applying across a codebase, since it survives whichever compiler version the build lands on. The third option in the dropdown, parens, goes further and requires parentheses around every operation, multiplication included, which surfaces arithmetic you forgot was there.

Legacy stylesheets are the common case for the Less 3 setting. Compile once under each mode and diff the two outputs. Any rule that differs is a division depending on the old behaviour, and those are the lines needing parentheses before you upgrade the build.

Parentheses decide whether a mixin appears in the output

This trips people up more than any other rule in the language. A ruleset defined with empty parentheses is a mixin and stays out of the CSS. The same ruleset without them is a class and gets emitted alongside every call site.

Mixin, not emitted.rounded() {border-radius: 10px;} .card { .rounded(); } .card { border-radius: 10px; }
Class, emitted twice.rounded {border-radius: 10px;} .card { .rounded; } .rounded { border-radius: 10px; } .card { border-radius: 10px; }

Both compile without complaint, so the only signal is dead weight in the output. If a utility class was meant to be reusable markup, drop the parentheses on purpose. If it exists only for other rules to pull in, keep them.

Arguments use semicolons when values contain commas

LESS accepts both separators in a mixin signature, and the comma loses whenever an argument holds a comma of its own. .shadow(0 1px 2px #000, 0 4px 8px #333) reads as two arguments. Write .shadow(0 1px 2px #000, 0 4px 8px #333;) with a trailing semicolon, or separate parameters with semicolons throughout, and the whole list arrives as one value.

The ampersand is a selector, not just a nesting shortcut

Inside a nested block, & stands for the full parent selector, and it works anywhere in the child selector rather than only at the front. Load the Nesting sample to see the three patterns worth knowing:

Repeating it doubles specificity: && compiles to .nav.nav. Useful for winning a fight with a third party stylesheet, and worth a comment when you use it.

Variables resolve at the end, not in order

LESS uses lazy evaluation. A variable takes the value of its last definition in the current scope, not the one above the line using it. This compiles to color: green:

@color: red;.box { color: @color; } @color: green;

Redefining a variable inside a block scopes the change to that block and everything nested under it. There is no mutation and no assignment order to reason about, which makes theme overrides straightforward and makes debugging a stray value harder. When the output surprises you, search for a second definition of the same name before anything else.

Interpolation and escaping

A variable used as a value needs no ceremony. A variable used inside a selector, a property name, a URL, or a media query needs @{braces}:

@side: left;@min: ~"(min-width: 48em)";.margin-@{side} { margin-@{side}: 12px; } @media @min { .nav { gap: 24px; } }

The tilde form passes a string through with no parsing. Media query conditions need it because LESS otherwise reads the colon and parentheses as its own syntax. The same escape covers CSS features the compiler predates, such as aspect-ratio: ~"16 / 9", where an unescaped slash meets the division rules described above.

Where this converter stops

Everything runs in your browser through the official Less compiler. Your source is never uploaded, which also sets the limits:

The minify option uses the compiler's own compressor, which strips whitespace and comments and nothing more. For real size reduction, feed the result to a dedicated minifier afterwards.

Related work in this category: the LESS Beautifier tidies the source before compiling, and the CSS Minifier squeezes the output afterwards.

LESS compilation questions

The problems people hit between a working LESS file and CSS a browser accepts.

Why does my division stop working after upgrading to Less 4?

Less 4 defaults to parens-division, so a slash outside parentheses is treated as a CSS separator instead of an operator. Wrap the expression in parentheses, as in width: (@grid / 3), and the result is identical under both versions. Switch the Division control above to Less 3 to confirm that a rule depends on the old behaviour.

Why is my mixin showing up as a class in the CSS?

A ruleset declared without parentheses is a normal class and gets written to the output as well as copied into every caller. Add empty parentheses to the definition, so .rounded() instead of .rounded, and the block stays out of the compiled file.

Can I compile a file that uses @import here?

No. The compiler runs in your browser with no access to your project files, so imported partials cannot be resolved. Paste the contents of each partial above your main source, or compile the files separately.

My compiled CSS is bigger than the LESS source. Is that wrong?

No, that is expected. Mixins copy their declarations into every call site and nesting expands into full descendant selectors, so output larger than input is the normal result. The percentage under the panes reports the difference on each compile.

Why does my variable have the wrong value?

LESS evaluates lazily and uses the last definition within a scope, not the nearest one above the usage. A redefinition further down the file wins. Search for a second declaration of the same name, and check whether a parent block redefines it.

How do I put a variable inside a media query or a selector?

Use interpolation with @{name}. Media query conditions also need escaping, as in @min: ~"(min-width: 48em)"; followed by @media @min. Without the tilde the compiler parses the colon and parentheses as its own syntax and reports an error.

Is my code sent to a server?

No. The Less compiler and the editors load in your browser and the compile runs on your machine. Nothing is transmitted, stored, or logged, which is also why imports and plugins are unavailable here.