MyInternships.in

CSS SASS

SASS Tutorial

SASS is the most popular CSS preprocessor. It lets you write cleaner, more maintainable stylesheets using variables, nesting, reusable mixins and functions — then compiles down to plain CSS that every browser understands. This tutorial walks through every core feature with side-by-side SCSS and compiled CSS.


What is SASS (and SCSS)?

SASS stands for Syntactically Awesome Style Sheets. It is a preprocessor: you write in an enhanced syntax with extra features, and a compiler turns it into ordinary CSS. The browser never sees SASS — it only ever runs the compiled .css file.

SASS ships with two syntaxes. The older indented syntax uses file extension .sass and no braces or semicolons. The newer, far more common syntax is SCSS (.scss), which is a strict superset of CSS — every valid CSS file is already valid SCSS, so you can rename a .css file to .scss and start adding features gradually. This tutorial uses SCSS throughout.

💡

Because SCSS is a superset of CSS, migrating is painless: rename styles.css to styles.scss and it still compiles. Then introduce variables and nesting one piece at a time.

How SASS compiles to CSS

You run a compiler (the Dart Sass CLI, or a build tool like Vite, Webpack or Parcel) that reads your .scss files and outputs .css. A typical command with the Dart Sass CLI looks like this:

Command line — compile and watch
# Install once (Node projects):
npm install -D sass

# Compile a single file
npx sass src/styles.scss dist/styles.css

# Watch for changes and recompile automatically
npx sass --watch src/styles.scss:dist/styles.css

Variables

SASS variables start with a dollar sign. They store colors, sizes, fonts or any value so you can reuse and change them from one place. Note that CSS now also has native custom properties (--name); SASS variables are resolved at compile time, while CSS variables live in the browser at runtime.

SCSS input
$brand: #0f766e;
$space: 16px;
$font-stack: system-ui, Arial, sans-serif;

.button {
  background: $brand;
  padding: $space;
  font-family: $font-stack;
}
Compiled CSS output
.button {
  background: #0f766e;
  padding: 16px;
  font-family: system-ui, Arial, sans-serif;
}

Nesting

Nesting lets you write child selectors inside their parent, mirroring your HTML structure. The ampersand refers to the parent selector — handy for states like :hover and BEM-style modifiers. Keep nesting shallow (2–3 levels) to avoid overly specific, brittle CSS.

SCSS input
.card {
  padding: 16px;
  border-radius: 8px;

  .title { font-weight: 700; }

  &:hover { box-shadow: 0 6px 20px rgba(0,0,0,.12); }
  &--featured { border: 2px solid #0f766e; }
}
Compiled CSS output
.card { padding: 16px; border-radius: 8px; }
.card .title { font-weight: 700; }
.card:hover { box-shadow: 0 6px 20px rgba(0,0,0,.12); }
.card--featured { border: 2px solid #0f766e; }

Partials and @use / @import

A partial is a small SCSS file whose name starts with an underscore (for example _buttons.scss). Partials are not compiled on their own; they are pulled into other files. The modern way to load a partial is @use, which namespaces its variables and mixins and only loads each file once. The old @import is deprecated in Dart Sass — prefer @use in new projects.

_variables.scss and main.scss with @use
// _variables.scss
$brand: #0f766e;
$radius: 8px;

// main.scss
@use "variables" as v;

.badge {
  background: v.$brand;
  border-radius: v.$radius;
}
ℹ️

With @use you access members through a namespace (v.$brand). Use @use "variables" as *; to import members without a prefix, but namespacing avoids naming collisions in larger codebases.

Mixins: @mixin and @include

A mixin is a reusable block of declarations you define once with @mixin and drop in anywhere with @include. Mixins can take arguments, including default values, which makes them perfect for repeated patterns like flex centering or media queries.

SCSS input
@mixin flex-center($dir: row) {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: $dir;
}

.hero { @include flex-center(column); }
.toolbar { @include flex-center; }
Compiled CSS output
.hero {
  display: flex; align-items: center; justify-content: center;
  flex-direction: column;
}
.toolbar {
  display: flex; align-items: center; justify-content: center;
  flex-direction: row;
}

Functions

SASS ships built-in functions for color, math and strings, and you can write your own with @function that return a value. Common built-ins include lighten(), darken(), mix(), percentage() and math.div(). Custom functions keep computed values readable and reusable.

SCSS input
@use "sass:math";

@function rem($px) {
  @return math.div($px, 16) * 1rem;
}

.title {
  font-size: rem(24);      // 1.5rem
  color: darken(#0f766e, 10%);
}
Compiled CSS output
.title {
  font-size: 1.5rem;
  color: #0a5049;
}

Inheritance with @extend and placeholders

@extend lets one selector inherit the styles of another, so shared rules are written once. Pair it with a placeholder selector (starting with %) that is never output on its own — only the selectors that extend it appear in the compiled CSS.

SCSS input
%alert-base {
  padding: 12px 16px;
  border-radius: 6px;
  font-weight: 600;
}

.alert-success { @extend %alert-base; background: #dcfce7; color: #166534; }
.alert-error   { @extend %alert-base; background: #fee2e2; color: #991b1b; }
Compiled CSS output
.alert-success, .alert-error {
  padding: 12px 16px;
  border-radius: 6px;
  font-weight: 600;
}
.alert-success { background: #dcfce7; color: #166534; }
.alert-error { background: #fee2e2; color: #991b1b; }
⚠️

Prefer mixins over @extend when the shared code takes arguments or when you want to avoid the long, grouped selector lists that @extend can generate. @extend is best for simple, argument-free shared bases.

Operators and math

SASS supports arithmetic (+, -, *, /, %) and comparison operators. Division now uses the math.div() function to avoid ambiguity with the CSS slash. Math is handy for building spacing scales and fluid grids at compile time.

SCSS input
@use "sass:math";
$gutter: 24px;

.col-4 { width: math.div(100%, 3); }        // 33.3333%
.stack > * + * { margin-top: math.div($gutter, 2); } // 12px
.wide { width: 200px + 50px; }               // 250px

Control flow: @if, @each, @for

SASS can generate repetitive CSS with loops and conditionals. @each iterates over a list or map, @for runs a counted loop, and @if branches — all at compile time, so the output is still plain static CSS.

SCSS input
$sizes: (sm: 4px, md: 8px, lg: 16px);

@each $name, $value in $sizes {
  .p-#{$name} { padding: $value; }
}
Compiled CSS output
.p-sm { padding: 4px; }
.p-md { padding: 8px; }
.p-lg { padding: 16px; }

Quick reference

FeatureSyntaxPurpose
Variable$name: value;Store and reuse a value
Nesting.a { .b { } }Write nested selectors
Parent ref&:hover { }Reference the enclosing selector
Partial_file.scssA reusable, non-compiled fragment
Load@use "file";Import a partial (modern)
Mixin@mixin / @includeReusable, parameterised block
Function@function / @returnReturn a computed value
Inheritance@extend %base;Share a set of declarations
💡

SASS is optional sugar on top of CSS — everything it does compiles to standard CSS. Learn plain CSS first, then reach for SASS to keep large stylesheets organised and DRY.

Related CSS Topics

Keep learning with these closely related tutorials.

Ready to use your CSS skills?

Find web development internships and fresher jobs across India.

Browse Web Dev Internships