Same compiler, same features, different punctuation
Sass ships two syntaxes for one language. The indented syntax came first in 2006 and uses the .sass extension. It borrowed its layout from Haml, so nesting is carried by whitespace and a statement ends where the line ends. SCSS arrived with Sass 3 in 2010 and uses the .scss extension. It kept braces and semicolons so that any valid CSS file is also a valid SCSS file.
Both feed the same compiler. Variables, mixins, functions, control directives, partials and the module system behave identically in either one. A project mixes both freely, since a .sass partial imports into a .scss file without complaint. Converting between them is a reformatting job, not a translation, which is why the panel above finishes the moment you stop typing.
| Element | SCSS | SASS |
|---|---|---|
| Block boundary | { } | Indentation |
| Statement end | ; | End of line |
| Silent comment | // note | // note |
| Loud comment | | , continuation lines indented |
| Mixin definition | @mixin name | @mixin name or =name |
| Mixin call | @include name | @include name or +name |
| Plain CSS pasted in | Works unchanged | Rejected until reformatted |
| Multi-line value | Allowed | Needs a backslash or one line |
What the converter does to each construction
Four transformations cover almost every line of a stylesheet. The rest of the file passes through untouched.
Braces become depth. Every opening brace pushes one indent level and the matching close pops it. Selectors, at-rules and nested property blocks all follow the same rule.
.card {padding: 1rem;&:hover {border-color: $brand;}}.card
padding: 1rem
&:hover
border-color: $brandNested properties keep their colon. The shorthand that splits font-family and font-size under a shared font prefix reads the same in both syntaxes. The trailing colon on the parent stays put, because dropping it would turn a namespace into a declaration with no value.
.title {font: {family: system-ui;weight: 650;}}.title
font:family: system-ui
weight: 650Interpolation is left alone. This is where find-and-replace scripts fall over. The braces in #{$size} are part of an expression, not a block, so counting braces naively either eats the variable or shifts every line below it one level deeper. The parser here tracks interpolation depth separately and copies the whole expression across as written.
.grid {width: calc(100% - #{$gutter});content: "a { b }";}.grid
width: calc(100% - #{$gutter})content: "a { b }"The quoted string in that example matters as much as the interpolation. A brace inside quotes belongs to the string value, and a converter that scans for punctuation without tracking quote state will treat it as a block and wreck everything after it.
Multi-line values fold onto one line. SCSS lets a long box-shadow or grid-template-areas spread across lines because the semicolon marks the end. Indented SASS ends the declaration at the newline, so a wrapped value needs joining first.
.panel {box-shadow:0 1px 2px rgba(0,0,0,.04),0 8px 24px rgba(0,0,0,.06);}.panel
box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.06)Long lines are the cost of that fold. If a joined value runs past your line limit, split it again with a trailing backslash, which is the one continuation marker the indented syntax accepts.
Read these lines before you commit the output
The notes panel under the editors lists what the parser had to make a decision about. Four cases come up often enough to name.
- Multi-line loud comments. A
block in a.sassfile ends when a line returns to the parent indent, so continuation lines get pushed one level deeper than the opening. The text survives, and the shape of an ASCII art banner does not. Re-read any comment that was carrying alignment. - Single-line rules. Writing
.a { color: red; }on one line is common in SCSS for tiny modifiers. Indented SASS has no equivalent, so each of those becomes two lines. A file full of one-line utilities grows taller after conversion even while the character count falls. - Trailing comments. A
//comment sitting after a declaration moves to its own line below it. The association still reads correctly, though a column of aligned end-of-line notes loses its alignment. - Unbalanced braces. An unclosed block leaves everything below it indented one level too deep, which produces valid-looking SASS that compiles into the wrong selectors. The panel counts unmatched braces in both directions and says so rather than guessing where the block was meant to close.
The indentation rules a .sass file enforces
The indented syntax is stricter about whitespace than most people expect on first contact, and the errors it raises are worth knowing in advance.
- Pick one indent character per file. Tabs or spaces, not both. Sass raises an error on a file that mixes them, even where the mixture is consistent inside each block. Whichever button you press above applies to the whole output.
- Keep the width consistent. Two spaces at one level and four at the next is an error. The compiler infers your unit from the first indented line and holds you to it.
- One level per step. Skipping from the parent to two levels deep is rejected outright rather than treated as extra nesting.
- Blank lines carry no meaning. They pass through and the converter preserves the ones you wrote, which keeps the visual grouping of a long file intact.
- At-rules lose their semicolons too.
@use "sass:math"and@import "reset"end at the newline like everything else.
Which syntax is worth the switch
Both compile to the same CSS, so this comes down to how the file gets written and read.
Reasons to move to indented SASS. Files shrink by a noticeable margin once the punctuation is gone, and git diffs stop showing lines that changed only by a brace. A missing semicolon stops being a failure mode. The indentation is enforced rather than agreed on in a style guide, so nesting depth becomes visible at a glance and deep nesting gets uncomfortable to write, which is a useful pressure.
Reasons to stay on SCSS. Pasting a rule from browser devtools or a vendor stylesheet works with no edits, and that alone decides it for many teams. The Sass documentation shows SCSS first, most published snippets and framework sources use it, and editor tooling has had far more attention pointed at the brace syntax. Bootstrap, Bulma and the rest ship .scss, so a project that overrides their variables lives in SCSS anyway.
The honest summary is that indented SASS suits a codebase written from scratch by a small team that agrees on it, and SCSS suits everything else. If you are converting an existing project, convert one partial, live with it for a week, and see whether the team reaches for the copy button or complains about pasted CSS breaking.
Where this converter stops
- It reformats, it does not compile. The output is Sass source, not CSS. To produce a stylesheet a browser reads, send the result through the SASS compiler or take the SCSS straight to the SCSS to CSS converter.
- It does not validate your SCSS. Undefined variables, a mixin called with the wrong arguments and a misspelled property all convert cleanly and fail later at compile time. Only brace balance gets checked, since that is what the indentation depends on.
- Shorthand at-rules stay long. Indented SASS allows
=namefor@mixinand+namefor@include. The output keeps the long forms, which are valid in both syntaxes and read the same to anyone arriving from SCSS. - Values are copied, not normalized. Spacing inside a declaration, quote style and colour notation come through exactly as you wrote them. Run the source through the SCSS beautifier first if you want consistent formatting on the way in.
- Large files run in the tab. Conversion is a single pass over the text and stays fast into the thousands of lines, though a framework-sized bundle of tens of thousands of lines will stutter on a phone. Convert partial by partial, which is how you should review the output anyway.
