Stylus is Sass's sibling, not its downgrade
Every other direction on this site turns a converter into a shrinkage report. Send SCSS to LESS and half the article is about the constructs LESS never grew. Stylus skips most of that problem. It has loops, conditionals, a hash type, and its own spelling for !default. The real story here is notation, not loss. Stylus made almost everything optional, punctuation included, so the same file can look like CSS with the sigils removed or like Python with curly braces gone entirely.
Read the notes panel before you trust the output. The workbench rewrites syntax it recognizes and leaves anything shaped like a Sass map exactly as written, colon and parentheses intact, because Stylus hashes use curly braces and guessing the rename would be worse than flagging it.
What the same construct looks like in each language
| Construct | SCSS | Stylus |
|---|---|---|
| Variable | $radius: 8px; | radius = 8px |
| Variable with fallback | $radius: 8px !default; | radius ?= 8px |
| Mixin definition | @mixin stack($gap: 12px) { } | stack(gap = 12px) |
| Mixin call | @include stack(16px); | stack(16px) |
| Function | @function tone($k) { @return map-get($t, $k); } | tone(k) return t[k] |
| Condition | @if $mode == dark { } | if mode == dark |
| Loop over a list | @each $c in $list { } | for c in list |
| Loop over a map | @each $k, $v in $map { } | for k, v in map |
| Extend | @extend .card; | @extend .card |
| Interpolation | .tone-#{$name} | .tone-{name} |
Two files, same rules
Stylus never forces one punctuation style. The compiler reads bracketed input identical to CSS and bare input with nothing but indentation, and a single file can even mix the two. The toggle above renders both from the same conversion pass, because a team standardised on Bootstrap-flavoured Stylus wants the left version and a team that picked Stylus specifically to avoid punctuation wants the right one.
brand = #c6538c
radius ?= 8px
.card {border-radius: radius;color: brand;&:hover {color: darken(brand, 10%);}}brand = #c6538c
radius ?= 8px
.card
border-radius: radius
color: brand
&:hover
color: darken(brand, 10%)Where the dollar sign actually goes
SCSS marks a variable at both ends, the $ on declaration and every use after it. Stylus needs neither. brand-pink = #c6538c declares it, color: brand-pink reads it, and the compiler tells variables from property names by position, not punctuation. The workbench strips every $ it finds, which is safe because Stylus reserves no other meaning for a bare identifier that happens to share a name with a color keyword. Custom properties are untouched on purpose. --brand on :root already runs at the browser, so a Stylus port of a file that bridges $brand into --brand for runtime theming keeps the double dash exactly as written.
Where Stylus already had the answer
Three Sass ideas that do not survive a LESS port land in Stylus with a native spelling, just a different one.
- Default values. Sass writes
!defaultafter the value. Stylus writes?=instead of=. Same lazy-only-if-unset behaviour, spelled as an operator rather than a flag, which is why the workbench treats it as a rename and not a leftover. - Hashes. Stylus objects use
{key: value}and read back withobj.keyorobj['key']. A Sass map close in shape,(key: value), needs the outer parentheses swapped for braces by hand, since guessing which nested values are meant to become nested hashes is not a job for a regex. - Iteration.
for val in listandfor key, val in hashcover what@eachdid in Sass, and a numericfor i in 1..12covers@for. The range operator is inclusive on both ends, so a Sass loop written withtoinstead ofthroughneeds its last iteration checked after conversion.
Where a human still has to look
- Sass maps.
$tones: (ink: #1a2420, leaf: #2a6b4a);keeps its Sass punctuation in the output. Swap the outer( )for{ }once you have renamed the variable, then switchmap-get($tones, ink)style lookups totones.inkortones['ink']. - Placeholder selectors.
%card-basehas no Stylus counterpart, silent or otherwise. The workbench turns it into an ordinary class, which means it now prints in the compiled CSS even on a page where nothing extends it. Delete the rule once every caller has moved to a real mixin, or accept the extra output. - Module namespaces.
@use "tokens" as tnarrows to a plain@import 'tokens'. Stylus merges imported names into one global scope the way old-style Sass@importdid, sot.$brandbecomes a barebrandwith no namespace to type. A private name that started with an underscore stops being private. - Content blocks.
@include stack { ... }passes a block the way@contentdoes. Stylus block mixins accept a block too, but it binds through ablockkeyword inside the callable rather than an explicit@contentmarker, so a converted call keeps its braces and needs the mixin body checked, not rewritten blind.
A pass you should still read
This is a syntax rewrite, not a compiler. It runs entirely in this tab, so nothing you paste reaches a server, and closing the page clears both panes. Four limits are worth knowing before you commit the result.
- One file at a time. A mixin imported from a partial reads as undefined here. Convert the partial that defines it first.
- Nothing is evaluated.
darken(brand-pink, 10%)keeps its name and arguments. Stylus ships the same color function, so this line usually just works, but arithmetic and string functions are copied, never run. - Top level variables only. The colon to equals rewrite applies to lines with no leading indentation, the common place to declare a Sass variable. An indented line is always read as a CSS property and keeps its colon, which is correct for a rule body and wrong only if your file declares variables inside a nested block, an unusual style.
- Comments stay untouched. Both
//andcompile the same way in Stylus, so nothing here strips or rewrites them, unlike a plain CSS nesting pass that has to throw comments away.
Who is still choosing Stylus
Stylus peaked alongside Jade and the early Express view-engine stack, and most of the requests for this converter now come from maintaining that era rather than starting it.
- An Express or Koa app scaffolded years ago that still ships
stylusas a build dependency, where the SCSS is a newer component someone wrote before checking what the project already used. - A component library that picked Stylus for the punctuation-free syntax and now needs to absorb a design token file a client sent over as SCSS.
- Teaching material or a style guide that shows the same component in three preprocessors, where Stylus is the one demonstrating how far optional syntax can go.
If none of that describes the project, compiling to plain CSS with the SCSS compiler is usually the shorter path. Reach for Stylus only when something already there requires it.
