One component, before and after
Six rules from a pricing card, written flat because plain CSS gives you no other option. Every rule repeats the parent selector, the hover state repeats it again, and the breakpoint lives wherever the media block happens to sit in the file.
.pricing-card { border: 1px solid #dfe2ec; border-radius: 12px; }
.pricing-card .plan-name { font-weight: 700; }
.pricing-card .plan-name a { color: #c6538c; text-decoration: none; }
.pricing-card .plan-name a:hover { color: #a33d70; }
.pricing-card.is-featured { border-color: #c6538c; }
@media (min-width: 768px) {.pricing-card { padding: 32px; }}$color-1: #c6538c;.pricing-card {border: 1px solid #dfe2ec;border-radius: 12px;@media (min-width: 768px) {padding: 32px;}
.plan-name {font-weight: 700;a {color: $color-1;text-decoration: none;&:hover {color: #a33d70;}}}
&.is-featured {border-color: $color-1;}}Four separate moves produced that block. Descendant selectors became nested blocks. The pseudo class and the modifier class folded onto the parent with an ampersand, because .pricing-card.is-featured targets the same element rather than a child. The brand pink appeared twice, so it got a name. And the breakpoint moved inside the block it modifies. Compile this file with Sass and the six original rules come back, in the same order, at the same specificity.
What each control changes
#app .layout .sidebar .menu-link keeps its first two blocks and the remaining parts arrive as one selector on the third. Set it to 1 to skip nesting entirely and use the page as a formatter with variable extraction attached.@media rule holding eight selectors becomes eight small @media blocks. Sass gathers them back at the bottom of the compiled file, so behaviour holds and the raw output grows a little before gzip. Off, breakpoints stay grouped at the end of the SCSS in source order.Which values turn into variables
Automatic naming goes wrong quickly, so extraction stays narrow on purpose. Three groups qualify once they hit the repeat threshold:
- Colors. Hex in three, four, six, or eight digits, the
rgb()andhsl()families, and the common named colors. These become$color-1and up. - Font stacks. Any
font-familyholding a comma, since a stack repeated across headings and body text is the clearest token in most stylesheets. - Function shaped values. Box shadows, gradients, transitions, filters, and transforms. The test is a pair of parentheses in the value or a property name in the shadow, transition, animation, or font family.
0 4px 22px rgba(21,22,28,0.08)repeated across six components is the single best argument for moving to Sass.
What stays exactly where it is:
- Single lengths. A
padding: 24pxwritten forty times stays24px. It becomes a token when you decide it is one, and$value-7reads worse than the number it replaced. - Custom properties. A
--brandon:rootalready does this job at runtime. Rewriting it as$brandmoves the value to compile time and breaks any theme switch reading it from JavaScript. - Blocks inside
@keyframesand@font-face. They pass through as written, colors included, because a variable dropped into a keyframe step tends to hide more than it saves.
The names are placeholders.$color-1, $shadow-2, and $font-1 are numbered in order of appearance, nothing more. Rename them to $brand-pink or $card-shadow before the file lands in a repository. A stylesheet built on $color-4 is harder to read than the hex codes it replaced, and the rename is the one part of this migration where a person adds real meaning. Use Copy variable block to pull the declarations into a _variables.scss partial while you do it.
Nesting rewrites more than the indentation
The output is a different file, not a reformatted one. Read the diff before you commit it, with these four behaviours in mind.
- Repeated selectors merge. A sheet declaring
.btnon line 12 and again on line 400 comes back as one block. The last declaration of a property still wins, so the compiled result usually matches, but unrelated rules sitting between the two shift position. Cascade conflicts settled by source order rather than specificity are the ones to check. - Comments are dropped. The parser reads selectors, declarations, and at-rules. Licence headers, section dividers, and the note explaining why a magic number exists do not survive. Copy them back by hand, and keep the original file until you have.
- Specificity does not drop.
#app .layout .linkstill scores an id plus two classes after compiling. Nesting hides that weight behind indentation, which makes an already heavy selector easier to live with and harder to notice. When specificity is the actual problem, flatter class names beat deeper nesting. - Nesting media queries duplicates them. Twelve blocks reacting to one breakpoint produce twelve
@mediawrappers in the SCSS. That is normal Sass practice and gzip absorbs most of it, though a site shipping uncompressed CSS should keep the switch off.
Everything runs inside your browser tab, so pasting a production stylesheet uploads nothing. A 4,000 rule sheet converts in a few dozen milliseconds. Past roughly 20,000 rules the output pane, not the parser, is what starts to drag, so convert a stylesheet at a time rather than a concatenated bundle.
Where this converter stops
What comes out is valid SCSS. Idiomatic Sass is a different target, and four parts of it need a person who knows the design:
- Mixins. A flex centering trio or a text truncation block repeated across components is the clearest case for
@mixin. Deciding which repeated group is a pattern and which is an accident takes knowledge of the product, not the syntax. - @extend and placeholder selectors. Same judgment call, with a real cost attached, since
@extendrewrites selector lists in ways that surprise people months later. Left out deliberately. - Partials and @use. One file goes in, one file comes out. Splitting the result into
_variables.scss,_card.scss, and an entry point is a directory decision tied to your build. - Maps and loops. Turning six colour declarations into an
@eachover a Sass map rewrites intent rather than syntax, and a converter guessing at intent produces code nobody trusts.
Syntax is the small half of moving a stylesheet onto Sass, and this page does that half properly. When you want to check the trade, run the result through the SCSS to CSS converter and compare the compiled output against the file you started with.
