SCSS in a nutshell
SCSS is the brace-and-semicolon syntax of Sass, the CSS preprocessor behind Bootstrap, Angular Material, many WordPress themes and countless design systems. Every valid CSS file is also valid SCSS, and on top of that you get $variables, nested selectors with &, @mixin and @include, %placeholder selectors with @extend, maps, @function, control flow with @if, @each and @for, and the module system built on @use and @forward. The older indented .sass syntax, without braces, is a different grammar and is not handled here.
Using the formatter
Paste the stylesheet or drop a .scss file onto the input. Sass variables, @mixin and #{} interpolation give it away, so detection picks SCSS over plain CSS automatically; if you are unsure, the header shows what was detected. Formatting runs as you type, Ctrl/Cmd+Enter reruns it on demand, and Ctrl/Cmd+K opens the command palette, where typing “tabs” switches the indentation without reaching for the mouse.
The engine is Prettier with its PostCSS-based SCSS parser, the same code that runs in editors and pre-commit hooks, bundled into the page. Your partials, including any internal hostnames or asset URLs inside them, are formatted on your own machine and are never sent to a server.
Layout settings
SCSS has no format-specific switches, because Prettier deliberately exposes very few for stylesheets. The one setting that matters is Indent in the toolbar: 2 spaces, 4 spaces or tabs per nesting level. Match whatever your Stylelint or EditorConfig setup enforces. Prettier aims to keep lines within 80 columns, and that limit is what decides when a long selector list or a mixin’s argument list gets broken across lines.
There is no SCSS minifier on this page. Sass compiles to CSS, so compress the compiled output instead with the CSS minifier.
What changes and what is preserved
Prettier normalises spacing rather than meaning. In practice that means:
- Each declaration goes on its own line with a space after the colon and a trailing semicolon, and
{stays on the selector line. - Sass maps such as
$breakpoints: (sm: 576px, md: 768px)are expanded to one key per line. } @else {is joined onto one line, matching the Sass documentation style.- Hex colours and units are lowercased, so
#FFFbecomes#fffand0PXbecomes0px, and leading zeros are added to decimals, so.2becomes0.2. - Multi-part values like a
transitionorbox-shadowwith several comma-separated layers are split one layer per line, indented under the property. - Both
//line comments and/* */block comments are kept where they were, and runs of blank lines collapse to a single one.
Nothing is evaluated. Variables are not substituted, @include is not expanded and @import paths are not followed, so a partial that references variables defined in another file formats fine on its own.
Things that trip people up
A missing } is the most common failure, and PostCSS reports it at the rule that was opened rather than at the end of the file, so start reading from the reported line. An unclosed /* comment swallows everything after it and produces its own error. Pasting compiled CSS is fine; pasting the indented .sass syntax is not, because without braces the parser cannot tell where a rule ends. Less files share a lot of surface syntax but use @ for variables; send those to the Less formatter instead.
Examples
Minified design-system partial
The map is expanded one breakpoint per line and the @each loop, media query and interpolated BEM modifier are nested cleanly.
@use "sass:math";$breakpoints:(sm:576px,md:768px,lg:992px);@function rem($px){@return math.div($px,16px)*1rem}%btn-base{display:inline-flex;padding:rem(8px) rem(16px)}.btn{@extend %btn-base;&--primary{background:$primary}@each $name,$width in $breakpoints{@media (min-width:$width){&--#{$name}-wide{width:100%}}}}@use "sass:math";
$breakpoints: (
sm: 576px,
md: 768px,
lg: 992px
);
@function rem($px) {
@return math.div($px, 16px) * 1rem;
}
%btn-base {
display: inline-flex;
padding: rem(8px) rem(16px);
}
.btn {
@extend %btn-base;
&--primary {
background: $primary;
}
@each $name, $width in $breakpoints {
@media (min-width: $width) {
&--#{$name}-wide {
width: 100%;
}
}
}
}
Theme mixin with control flow, 4-space indent
The @if and @else branches line up, the // comment stays beside its @include, and .1 gains a leading zero.
@mixin theme($dark:false){@if $dark{background:#111;color:#eee}@else{background:#fff;color:#222}}
.panel{@include theme($dark:true);// single-line comment survives
.panel__header{border-bottom:1px solid rgba(#000,.1)}}@mixin theme($dark: false) {
@if $dark {
background: #111;
color: #eee;
} @else {
background: #fff;
color: #222;
}
}
.panel {
@include theme($dark: true); // single-line comment survives
.panel__header {
border-bottom: 1px solid rgba(#000, 0.1);
}
}
Card component with uppercase values
Hex colours and units are lowercased and the two transition layers are placed on separate lines.
.card{color:#1F2937;margin:0PX auto;transition:opacity .3s ease-in-out,transform .3s ease-in-out;&:hover{transform:translateY(-2PX)}}.card {
color: #1f2937;
margin: 0px auto;
transition:
opacity 0.3s ease-in-out,
transform 0.3s ease-in-out;
&:hover {
transform: translateY(-2px);
}
}
Common errors and how to fix them
| Error | Cause | Fix |
|---|---|---|
CssSyntaxError: Unclosed blockExplained | A rule, mixin or @if branch was opened with { and never closed, often after deleting a nested block. | Count braces from the reported line downward and add the missing }. |
CssSyntaxError: Unexpected } | There is one closing brace too many, usually left behind when a nested selector was cut out. | Remove the stray } at the reported column, or restore the opening brace it belonged to. |
CssSyntaxError: Unknown word color | A declaration is missing its colon, as in color red, so the parser cannot tell a property from a selector. | Write the declaration as property: value; with a colon. |
CssSyntaxError: Unclosed comment | A /* block comment was never closed, so the rest of the file became part of the comment. | Add */ where the comment should end, or switch to // for a single-line note. |
CssSyntaxError: Unclosed string | A quoted value such as a content string or font name is missing its closing quote. | Close the quote on the same line as it was opened. |
Frequently asked questions
Is this the same as running Prettier on my .scss files?
Yes. It is Prettier with the SCSS parser, so with the same indent and the default 80-column width the output matches what your editor or a prettier --write run would produce.
Can it format the indented .sass syntax?
No. Only the SCSS syntax with braces and semicolons is supported. Convert .sass files with sass-convert or the Sass CLI first.
Does the formatter compile SCSS to CSS?
No. It only reformats the source. Variables, mixins and imports are left as they are; compile with Dart Sass to get CSS.
Why did my uppercase hex colours become lowercase?
Prettier lowercases hex colours and units as part of its stylesheet style. Browsers treat both cases the same, so rendering is unaffected.
Will it reorder my properties?
No. Declarations stay in the order you wrote them. Use a Stylelint plugin such as stylelint-order if you want properties sorted.