An online Sass compiler for learning the indented syntax
The indented syntax is Sass without braces: indentation shows nesting and a line break ends a declaration. It is quick to write once you know its rules, and easy to get subtly wrong before you do. This online Sass compiler runs Dart Sass 1.x on every edit, so you can see how each indent changes the CSS and learn the syntax by experimenting.
Compiling complete .sass files for a project? SASS to CSS uses the same compiler with expanded output and no options. This page adds Minify output and concentrates on the syntax itself. If you write braces and semicolons, the SCSS compiler is the right place.
Shorthand you can try
=button($bg: #0f766e)
background: $bg
color: white
&:hover
opacity: .9
.save
+button
.delete
+button(#b91c1c)
.save {
background: #0f766e;
color: white;
}
.save:hover {
opacity: 0.9;
}
.delete {
background: #b91c1c;
color: white;
}
.delete:hover {
opacity: 0.9;
}
=name defines a mixin and +name includes it. The long forms @mixin and @include work too, so you can switch between them while learning. Arguments with defaults behave exactly as in SCSS: +button used the default color, while +button(#b91c1c) replaced it. Note how the nested &:hover inside the mixin produced a separate rule for each class that included it.
Nested properties
A property that ends in a colon can hold sub-properties on the following, deeper-indented lines:
$gap: 8px
.card
padding: $gap * 2
&__title
margin:
bottom: $gap
.dark &
background: #111
.card {
padding: 16px;
}
.card__title {
margin-bottom: 8px;
}
.dark .card {
background: #111;
}
This feature explains one of the traps below: an extra space can accidentally turn a line into a sub-property.
Indentation traps that do not raise errors
Some mistakes compile without complaint and simply produce different CSS. Each of these was run through this compiler.
One space too many
.a
color: red
width: 10px
.a {
color: red;
color-width: 10px;
}
The extra space nested width under color as a sub-property.
A missing colon
.a
color red
This produces no CSS at all. Without a colon, the line reads as a nested selector with an empty body.
A missing indent
nav
a
color: red
nav {
color: red;
}
color sits at the same level as a, so it belongs to nav, and the empty a rule vanishes.
After every change, check that the CSS contains the selectors and properties you intended. The live output makes this a habit rather than a chore. A reliable routine is to count the rules: if you wrote three selectors and see two, look for a line that lost or gained an indent. Most editors can show whitespace characters, which makes stray spaces and tabs visible at a glance.
Errors the compiler does report
- Expected tabs, was spaces. The file started indenting with tabs and a later line uses spaces (or the other way round). Pick one.
- Expected newline. Usually a brace copied from SCSS or CSS, such as
.a {. - expected selector. A line like
width 10pxafter a declaration; add the missing colon. - Undefined variable. or Undefined mixin. A typo, or a definition from a file you did not paste.
Each message includes the line and column, and the line is highlighted in the editor. Trailing semicolons, by contrast, are tolerated by the Dart Sass version used here, although they are unnecessary in the indented syntax.
Loops and modules work the same
Everything else in Sass carries over unchanged. A quick loop shows the indentation-only style:
@use 'sass:math'
$cols: 4
@for $i from 1 through $cols
.w-#{$i}
width: math.percentage(math.div($i, $cols))
This compiles to four classes, .w-1 to .w-4, with widths of 25%, 50%, 75% and 100%. Built-in modules load normally; your own partials cannot, because the compiler has no access to your files.
Moving between syntaxes
To see the compiled styles written as SCSS, use SASS to SCSS; for the reverse direction there is SCSS to SASS. Both go through CSS, so variables and mixins end up as plain values. Compilation runs in your browser.