Skip to content
Home
CSS Preprocessors: Sass, Less, and Stylus

CSS Preprocessors: Sass, Less, and Stylus

Web Development Web Development 8 min read 1658 words Beginner ExcellentWiki Editorial Team

CSS preprocessors extend CSS with programming features — variables, nesting, mixins, functions, and modular file organization — that compile down to standard CSS. They eliminate repetition, improve maintainability, and bring structure to stylesheets.

What Is a Preprocessor?

A preprocessor takes a custom syntax and compiles it to plain CSS:

Source (Sass/Less/Stylus)  →  Preprocessor  →  Output CSS

All three preprocessors offer similar features. The choice often comes down to ecosystem and team preference.

Sass (Syntactically Awesome Style Sheets)

Sass is the most widely used CSS preprocessor. Two syntaxes:

  • SCSS (.scss): Superset of CSS, most popular
  • Indented syntax (.sass): Uses indentation instead of braces

Variables

$primary-color: #3498db;
$spacing-unit: 8px;
$font-stack: 'Inter', system-ui, sans-serif;

.header {
  background-color: $primary-color;
  padding: $spacing-unit * 2;
  font-family: $font-stack;
---

Nesting

.navbar {
  background: #333;
  padding: 1rem;

  .nav-list {
    display: flex;
    list-style: none;
    margin: 0;
  }

  .nav-item {
    margin-right: 1rem;

    a {
      color: white;
      text-decoration: none;

      &:hover {
        text-decoration: underline;
      }
    }
  }

  &--dark {
    background: #111;
  }

  &__link {
    font-weight: 600;
  }
---

Mixins

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

.card {
  @include flex-center(column);
  padding: 2rem;
---

.hero {
  @include flex-center;
  min-height: 80vh;
---

Functions

@function rem($px, $base: 16px) {
  @return ($px / $base) * 1rem;
---

@function contrast-color($bg) {
  @if lightness($bg) > 50% {
    @return #000;
  } @else {
    @return #fff;
  }
---

.element {
  font-size: rem(24);
  color: contrast-color($primary-color);
---

Partials and Imports

In modern Dart Sass, use @use and @forward instead of @import:

// _variables.scss
$primary: #3498db !default;

// main.scss
@use 'variables' as v;
@use 'mixins';

.header {
  color: v.$primary;
  @include mixins.card;
---

Less

Less is the precursor to many Sass features. Variables use @ instead of $. Mixins use class selectors without a @mixin keyword.

@primary-color: #3498db;
@spacing: 8px;

.flex-center(@direction: row) {
  display: flex;
  flex-direction: @direction;
  align-items: center;
  justify-content: center;
---

.container {
  .flex-center(column);
---

Less integrates naturally with CSS syntax — valid CSS is valid Less. The .less extension is required, but the syntax is closer to standard CSS than SCSS.

Stylus

Stylus has the tersest syntax — braces, colons, and semicolons are all optional.

primary-color = #3498db

flex-center(direction = row)
  display flex
  flex-direction direction
  align-items center
  justify-content center

.container
  flex-center(column)

Stylus also supports transparent mixins (functions that look like properties) and interpolation for vendor prefixes. Its free-form syntax appeals to developers who value conciseness.

Comparison

| Feature | Sass (SCSS) | Less | Stylus | |

Beyond Variables and Nesting

Modern CSS preprocessors (Sass, Less) offer advanced features that significantly improve stylesheet maintainability:

Mixins with Logic

Sass mixins can include conditional logic and loops, making them far more powerful than simple property groups:

@mixin responsive-spacing($property, $min, $max) {
    #{$property}: $min;
    @media (min-width: 768px) {
        #{$property}: calc(#{$min} + (#{$max} - #{$min}) * ((100vw - 768px) / (1440 - 768)));
    }
    @media (min-width: 1440px) {
        #{$property}: $max;
    }
---

.card {
    @include responsive-spacing(padding, 1rem, 3rem);
---

Placeholder Selectors

Placeholder selectors (%) define styles that are only output when extended, avoiding class duplication in compiled CSS:

%card-base {
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    overflow: hidden;
---

.product-card { @extend %card-base; background: white; }
.article-card { @extend %card-base; background: #f5f5f5; }

Color Functions

Preprocessors provide powerful color manipulation functions that are not yet available in native CSS:

$primary: #3498db;

.button {
    background: $primary;
    &:hover {
        background: darken($primary, 10%);
    }
    &:active {
        background: darken($primary, 15%);
    }
    &--secondary {
        background: lighten($primary, 30%);
        color: $primary;
    }
---

Build Tool Integration

Modern build tools like Vite, Webpack, and Parcel handle Sass compilation seamlessly with minimal configuration:

# Vite — install the preprocessor, Vite handles compilation
npm install -D sass

# Webpack with sass-loader
npm install -D sass sass-loader css-loader style-loader

Rename your .css files to .scss and the build pipeline processes them automatically. For production, all tools include minification and vendor prefixing through PostCSS autoprefixer.

Modular Architecture with Partials

Organize Sass files following the 7-1 architecture pattern popularized by Hugo Giraudel:

// abstracts/ — variables, functions, mixins
// vendors/ — third-party CSS
// base/ — reset, typography
// layout/ — grid, header, footer
// components/ — buttons, cards, modals
// pages/ — page-specific styles
// themes/  theme variables

The main file imports all partials in order, with variables first and overrides last:

@use 'abstracts/variables';
@use 'abstracts/functions';
@use 'abstracts/mixins';
@use 'vendors/normalize';
@use 'base/reset';
@use 'layout/grid';
@use 'components/button';
// ...

The @use rule (Sass 3.x+) creates namespaced imports, avoiding the global namespace pollution of @import. This prevents naming conflicts and makes dependency tracking explicit.

Performance Implications

Preprocessors add a build step. For small projects, the build overhead is negligible. For large projects with thousands of partials and deep nesting, compile times can reach seconds. Consider:

  • Limiting nesting depth to 3-4 levels maximum
  • Avoiding mixins with large amounts of generated CSS (use @extend or CSS custom properties instead)
  • Using purging to remove unused CSS in production (PurgeCSS, Tailwind’s built-in purging)
  • Precompiling critical CSS inline and deferring the rest

PostCSS and Autoprefixing

PostCSS transforms CSS with JavaScript plugins. Combined with Autoprefixer, it ensures cross-browser compatibility without manual vendor prefixes:

npm install -D postcss autoprefixer postcss-cli
// postcss.config.js
module.exports = {
    plugins: [
        require("autoprefixer"),
        require("postcss-preset-env")({ stage: 2 }),
    ],
---;

PostCSS runs as part of the build pipeline in most modern toolchains (Vite, Webpack with postcss-loader). Autoprefixer uses data from Can I Use to determine which vendor prefixes are needed for the browser support targets defined in your project’s browserslist configuration.

CSS Next: Future Features Today

PostCSS plugins enable future CSS features today. postcss-preset-env converts modern CSS (custom properties, nesting, oklch() colors, :has() selector) to browser-compatible CSS. This allows you to write modern CSS while supporting older browsers. As browsers implement these features natively, you can drop the PostCSS transforms without changing your source CSS.

—|—|—|—| | Variables | $var | @var | var (no prefix) | | Nesting | & | & | & | | Mixins | @mixin / @include | Class selectors | Direct calls | | Functions | @function | Less.js functions | Native functions | | Conditionals | @if / @else | Guards | if / unless | | Loops | @each / @for | Not built-in | for / while | | Extend | @extend | :extend() | @extend | | Ecosystem | Largest | Moderate | Smallest |

Build Integration

CSS preprocessors require build tool integration. Webpack uses sass-loader, less-loader, or stylus-loader. Vite has built-in support — just install the preprocessor package. The @use directive replaces @import in modern Sass, providing better encapsulation and namespace control.

Preprocessor vs PostCSS

PostCSS transforms CSS with JavaScript plugins rather than extending CSS syntax. It can import files (postcss-import), add vendor prefixes (autoprefixer), nest selectors (postcss-nesting), and use future CSS features (postcss-preset-env). The choice between preprocessors and PostCSS depends on team preference — both handle variables, nesting, and mixins, but PostCSS uses standards-track syntax while preprocessors introduce custom syntax.

Best Practices

  1. Use a naming convention: BEM with SCSS nesting (block__element--modifier)
  2. Limit nesting depth: 3 levels max — deeper generates overly specific selectors
  3. Avoid over-mixing: Do not create mixins for every repeated property
  4. Use variables for design tokens: Colors, spacing, fonts, breakpoints
  5. Organize by component: One partial per component (_card.scss, _navbar.scss)
  6. Output sensible CSS: Review compiled CSS for selector bloat

Summary

Sass is the industry standard with the largest ecosystem. Less is simpler and integrates naturally with CSS syntax. Stylus offers the most concise syntax. All three provide variables, nesting, mixins, and modular organization. Choose Sass for broad compatibility and tooling, Less for simple projects, and Stylus if you prefer minimal syntax.

FAQ

What is the difference between SCSS and Sass? SCSS (Sassy CSS) uses curly braces and semicolons — it is a superset of CSS. Sass (the indented syntax) uses indentation instead of braces. SCSS is more popular because it is easier to adopt incrementally in existing CSS projects.

Should I use @import or @use in Sass? Use @use and @forward. The @import directive is deprecated in Dart Sass. @use provides namespace control, better encapsulation, and prevents variable name conflicts.

Can I use CSS preprocessors with CSS-in-JS? No. CSS preprocessors work with CSS files and compile to standard CSS. CSS-in-JS libraries handle variables, nesting, and logic through JavaScript — they do not need a preprocessing step.

What is the learning curve for each preprocessor? SCSS is easiest if you know CSS — valid CSS is valid SCSS. Less has the gentlest learning curve because it stays close to CSS syntax. Stylus has the steepest curve because its syntax is significantly different.


Related: CSS Variables Guide | Responsive Design

Related Concepts and Further Reading

Understanding css preprocessors requires familiarity with several interconnected ideas and principles that together form a complete picture. Exploring these related concepts deepens your knowledge and provides context that makes the core material more meaningful and applicable. Each concept builds on the others, creating a web of understanding that supports deeper learning and practical application. Taking time to explore how these elements connect reveals patterns that accelerate comprehension and retention of new information.

The relationship between css preprocessors and adjacent fields is worth particular attention. Many of the most important insights emerge at the boundaries between disciplines, where ideas from different areas combine to create new approaches and solutions that neither field could produce alone. Exploring these connections pays dividends in both breadth and depth of understanding, revealing patterns and principles that might otherwise remain hidden from view. Cross-disciplinary knowledge is increasingly valued as problems become more complex and interconnected.

For those looking to go beyond introductory material, several excellent resources provide deeper treatment of specific aspects of css preprocessors. Academic journals, industry publications, authoritative reference works, and online courses each offer different perspectives and levels of detail. The key is to match your reading to your current learning goals and build knowledge progressively, focusing on quality over quantity in your study materials. A well-chosen resource that matches your current level is worth more than dozens of resources that are too basic or too advanced.

Section: Web Development 1658 words 8 min read Beginner 756 articles in section Report inaccuracy Back to top