Stylus to CSS Converter

Paste a .styl file and read the CSS a browser gets. Variables resolve to values, mixins expand in place, nesting flattens to full selectors, and every line the compiler skipped is listed under the output with its reason.

Stylus compile bench

  • 0 rules
  • 0 declarations
  • 0 variables resolved
  • 0 mixins expanded

Stylus source .styl

Compiled CSS .css

Output refreshes as you type. Nothing leaves the tab.

Compile notes

Paste Stylus on the left. Notes about skipped lines will show here.

    A compile, not a translation

    The other Stylus pages on this site rewrite syntax. LESS wants braces back, SCSS wants a dollar sign in front of every variable. Plain CSS wants none of the Stylus machinery at all, so this page runs your code instead of rewording it. A variable named brand does not become --brand or $brand. The hex value gets written wherever the name stood. A mixin does not survive as anything. Its body lands inside each rule which called it, with the arguments filled in. Nothing in the output reads as Stylus, because a browser has no idea what Stylus is.

    The same file, before and after:

    Stylus in
    brand = #1f6f8b
    gap = 12px
    button(bg)background bg
    &:hover
    background darken(bg, 12%).toolbar
    padding (gap * 2) gap
    a.cta
    button(brand)&-title
    font-weight 600
    CSS out
    .toolbar {padding: 24px 12px;}
    .toolbar a.cta {background: #1f6f8b;}
    .toolbar a.cta:hover {background: #144759;}
    .toolbar-title {font-weight: 600;}

    Four Stylus ideas went in: two variables, one mixin with a nested hover, and a parent reference used as a BEM suffix. Zero came out. The arithmetic ran, the colour function ran, the selectors were joined. This is the same result the stylus binary prints for the file, minus one detail covered under where the real compiler still wins.

    What each construct becomes

    The ledger below is the whole contract. Green rows resolve without your help. Amber rows produce output plus a note in the panel under the editors. Grey rows produce nothing, on purpose, because Stylus itself prints nothing for them.

    Stylus lineWhat the CSS showsHandling
    brand = #1f6f8b then color brandcolor: #1f6f8b;Resolved
    .card with .title indented under it.card .title {Flattened
    &:hover, &-title.card:hover, .card-titleFlattened
    padding (gap * 2) gappadding: 24px 12px;Evaluated
    button(brand) or button brandThe mixin body, inline, with bg replacedExpanded
    @media tablet nested inside .toolbar@media ... { .toolbar { } } at the top levelBubbled up
    @extend .btn inside .btn-alt.btn, .btn-alt { on the extended ruleMerged
    darken(), lighten(), rgba(#000, .2), unit(), s()The computed valueEvaluated
    @keyframes, @font-face, @supportsThe same at-rule with braces and semicolonsKept
    Kept in both output formatsKept
    Kept in Expanded, dropped in CompactKept
    // line commentNothing. Stylus never prints these.Dropped
    @import "reset.css"@import "reset.css";Kept
    @import "mixins" (a .styl file)The same import line, unresolvedKept, noted
    if, unless, for, while blocksNothingSkipped, noted
    add(a, b) with a return lineCalls stay as add(1, 2)Left, noted
    +block-mixin() with a {block} bodyNothingSkipped, noted
    An empty rule with no declarationsNothingDropped

    How the notes panel earns its place

    A syntax rewriter fails quietly. It emits something which looks like CSS, and you find out in the browser when a rule does nothing. A compiler has to decide what a line means, so a line with no meaning is caught at the point of failure. Every one of those lines goes into the panel under the editors with its line number, the source text, and one sentence on why nothing came out. An empty panel reading "clean compile" means every source line is accounted for in the CSS. A panel with entries means read them before the file ships. Most of the time the fix is a one-line edit in the Stylus, not in the output.

    The count in the top bar tells the other half of the story. If you pasted 40 lines with three variables and the bar reads zero variables resolved, the names were never used in a value, or they were defined after the lines using them. Stylus reads top to bottom, and so does this page.

    Three checks before the output ships

    1. Division only happens inside parentheses.font 16px/1.5 sans-serif comes out as the shorthand, untouched, because Stylus treats a bare slash in a property as a literal. width 100% / 3 also stays literal, which is a surprise to people arriving from Sass. Write width (100% / 3) and the output reads 33.333%. Addition, subtraction and multiplication run without the parentheses as long as the operator has a space on each side.
    2. Variables named after CSS keywords resolve like any other.Define red = #c0392b and every later color red becomes the hex. The real compiler does the same. If you see a keyword in the output where you expected a hex, the assignment sits below the first use, or lives in a file this page never saw.
    3. Mixins with block arguments do not expand.A call written as +wrapper() with an indented body underneath is a block mixin. The page files a note and skips the call rather than guess at the output. Rewrite the mixin to take plain arguments, or compile the one partial with the Stylus CLI.

    Where the real compiler still wins

    This is a subset of Stylus, chosen to cover the constructs which appear in ordinary component files. The gaps are deliberate, and each one produces a note rather than silent output:

    Use this page for a component, a snippet from a blog post, a legacy theme file you need to read as CSS today, or a quick check on what a mixin expands to. For a build step, install the package and run stylus -p src/main.styl. The CLI reads your imports, runs your functions, and prints the exact bytes your users get. Nothing in a browser tab should be the source of truth for a production stylesheet.

    Is plain CSS the right stop?

    Native nesting shipped in every major browser in 2023. Custom properties have been there since 2016. Colour math arrived as color-mix() in the same window. Most of what Stylus gave a team in 2014 is now spelled in CSS itself, which is why the answer for a team leaving Stylus is usually plain CSS, not another preprocessor.

    Two edits are worth making on the compiled output before you commit it. Anything you would want to change at runtime, a brand colour, a spacing scale, a theme switch, goes back into a --custom-property on :root. The compiled hex is fine for constants, and a variable in the source is a hint about which values were meant to change. Second, leave the flattened selectors alone. Native nesting is optional, the flat form is what every tool in your pipeline already understands, and a diff against the old compiled CSS is easier when the selectors match line for line.

    Where plain CSS still falls short: mixins with logic, loops which generate utility classes, and colour functions with arguments computed at build time. If your Stylus leans on those, target SCSS and keep a compile step. If you have a LESS pipeline waiting, use Stylus to LESS instead. And if this page compiled your file with an empty notes panel, a preprocessor is dead weight in your build.

    Stylus compile questions

    What people ask after their first compile on this page.

    Why does the output show a selector I never wrote, like .btn, .btn-alt?

    A rule in your Stylus extended another one. Extend works by adding the extending selector to the target rule, so the target now matches both. This is the same output the Stylus CLI produces. If the pairing is wrong, the target string in your extend line matched a wider selector than you intended.

    A rule from my source is missing in the CSS. Where did it go?

    Two reasons cover nearly every case. A rule with no declarations of its own is dropped, because Stylus prints nothing for an empty block. Or the rule sat inside a control flow block, which this page skips. Check the notes panel first. If the panel is clean and the rule is still missing, it was empty after its nested rules were lifted out.

    Which comments survive the compile?

    Double-slash line comments never reach the CSS, matching Stylus. Block comments survive in the Expanded format. A block comment starting with a slash, star and exclamation mark survives in both formats, which is the convention for licence headers.

    My Stylus uses braces and semicolons. Does it still work?

    Yes. Both dialects are accepted, and a file which mixes them line by line compiles too. When any line ends in an opening brace, nesting is read from the braces instead of the indentation, so a braced file with sloppy indentation still parses.

    Is the CSS byte for byte identical to the stylus CLI?

    For the covered subset it matches in structure and values. Three cosmetic differences remain: numbers are rounded to three decimals here, comma-separated selectors are printed one per line, and darkened or lightened colours are printed as hex where the CLI sometimes prints rgba. Diff the two once if the difference matters to your build.

    Does my Stylus leave the browser?

    No. The compiler is a JavaScript file loaded with the page, and both editors live in memory in your tab. There is no upload, no server call, and nothing is stored after you close the page.