User Rating 0.0
Total Usage 0 times
Category CSS Tools
LESS Input 0 lines
SCSS Output 0 lines
Is this tool helpful?

Your feedback helps us improve.

About

Migrating a codebase from LESS to SCSS is not a find-and-replace job. LESS uses @ for variables while SCSS uses $, but @ also prefixes CSS at-rules like @media and @keyframes. A naive substitution breaks every media query in the project. LESS mixin syntax overloads class selectors, meaning .border-radius() is both a callable mixin and a valid CSS class pattern. Guard expressions (when) have no direct SCSS equivalent and must map to @if blocks. This converter handles those edge cases: variable scoping, string interpolation (~"..."#{...}), mixin detection with parameter preservation, extend rewriting, and function renaming (spinadjust-hue, fadergba). It operates entirely in the browser with no server round-trip.

Limitations: deeply nested mixin namespaces and JavaScript-evaluated expressions (`...` backtick blocks) have no SCSS equivalent and are flagged as warnings rather than silently mangled. Programmatic LESS features like recursive mixin pattern-matching require manual refactoring. The tool approximates conversion for roughly 95% of real-world LESS codebases. Always diff the output against your original and run your test suite before committing.

less to scss less converter scss converter css preprocessor less migration stylesheet converter less to sass

Formulas

The converter applies a deterministic pipeline of regular expression transformations in strict order. Each stage mutates the source string exactly once. The pipeline sequence matters: variables must be converted before mixin parameters, and at-rule exclusion must precede variable substitution.

Stage 1 - Variable Declaration: @name: value $name: value

Exclusion set = { @media, @import, @keyframes, @font-face, @charset, @supports, @page, @namespace, @layer }

Stage 2 - Interpolation: @{name} #{$name}

Stage 3 - Mixin Definition: .name(params) { @mixin name(params) {

Stage 4 - Mixin Call: .name(args); @include name(args);

Stage 5 - Guard: when (cond) @if (cond)

Stage 6 - Extend: &:extend(.sel) @extend .sel;

Stage 7 - Function Renames: spin adjust-hue, e unquote, fade rgba

where name = any valid CSS identifier matching [a-zA-Z_][a-zA-Z0-9_-]*, params = comma-separated parameter list with optional defaults, cond = boolean expression from LESS guard syntax, .sel = any valid CSS selector.

Reference Data

LESS SyntaxSCSS EquivalentNotes
@variable: value;$variable: value;Prefix swap. At-rules excluded.
@{variable}#{$variable}String interpolation in selectors & properties.
~"expression"unquote("expression")Escape hatch for raw CSS output.
.mixin() { }@mixin mixin() { }Parenthesized LESS class = mixin definition.
.mixin();@include mixin();Mixin call detected by trailing semicolon.
.mixin(@a, @b)@mixin mixin($a, $b)Parameters converted recursively.
.mixin() when (@a > 0)@mixin mixin() { @if ($a > 0) { ... } }Guard → conditional block.
&:extend(.class)@extend .class;Extend syntax normalization.
:extend(.class)@extend .class;Standalone extend form.
spin(color, deg)adjust-hue(color, deg)Color function rename.
fade(color, 50%)rgba(color, 0.5)Opacity conversion: 50%0.5.
fadein(color, 10%)lighten(color, 10%)Approximate mapping.
fadeout(color, 10%)darken(color, 10%)Approximate mapping.
e("text")unquote("text")Direct function rename.
.class when (default())@mixin class() { @else { ... } }Default guard → else branch. Manual review recommended.
#namespace > .mixin()@include mixin();Namespace stripped. Flagged as warning.
@import "file.less"@import "file"Extension removed per SCSS convention.
@arguments$args...Rest parameter mapping. Context-dependent.
`javascript` - No SCSS equivalent. Flagged as error.
& when (...)@if (...) { & { ... } }Parent selector guard.

Frequently Asked Questions

The converter maintains an exclusion set of all standard CSS at-rule keywords: @media, @import, @keyframes, @font-face, @charset, @supports, @page, @namespace, @document, @counter-style, and @layer. The variable replacement regex uses a negative lookahead that skips any @ token immediately followed by one of these keywords. Custom at-rules are not in the exclusion set and will be converted - review any framework-specific at-rules in your output.
Partially. The converter strips the namespace prefix (#bundle >) and converts the mixin call to @include mixin(). However, SCSS has no direct equivalent of LESS namespaces. If your codebase relies on namespace collision avoidance, you must manually refactor the SCSS output to use module partials (@use with namespace) or rename conflicting mixins.
Backtick expressions like `Math.round(...)` have no SCSS equivalent. The converter wraps them in a comment /* LESS_JS_EVAL: ... */ and emits a warning in the conversion log. You must replace these with native Sass functions, custom Sass functions, or pre-computed values.
Yes. LESS fade(@color, 50%) sets opacity to 50%. The converter transforms this to rgba(@color, 0.5) by dividing the percentage value by 100. It handles integer and decimal percentages (e.g., fade(@c, 33.3%) becomes rgba($c, 0.333)). If the percentage argument is itself a variable, the converter wraps it in an arithmetic expression: ($var / 100).
The heuristic uses brace-depth context. A pattern like .name(@params) followed by { on the same or next non-empty line is classified as a mixin definition and converted to @mixin. The same pattern followed by ; is classified as a mixin call and converted to @include. Ambiguous cases - such as a class selector .btn() that is neither a mixin definition nor call but a CSS class with parentheses - are flagged as warnings. Review all warnings after conversion.
The converter strips .less extensions from @import statements (e.g., @import "variables.less" becomes @import "variables"). It does not rename imported files to the SCSS partial convention (_variables.scss). You must rename the actual files on disk yourself. The converter also does not change @import to @use or @forward - that requires understanding your dependency graph, which is a project-level decision.