¿Qué es Sass?
Sass significa Syntactically Awesome Style Sheets. Es un preprocesador de CSS: un lenguaje que extiende el CSS convencional con funcionalidades de programación y se compila a CSS estándar que los navegadores pueden entender. Si alguna vez te has encontrado repitiendo valores de color, duplicando media queries o navegando entre cientos de líneas de CSS plano, Sass es la herramienta que resuelve esos problemas.
Creado por Hampton Catlin en 2006, Sass fue el primer preprocesador de CSS en lograr una adopción masiva. Introdujo conceptos de lenguajes de programación de propósito general —variables, anidamiento, funciones, bucles y módulos— en el mundo de las hojas de estilo. Hoy en día es la base de proyectos como Bootstrap, Foundation y un sinnúmero de sistemas de diseño.
La mejor manera de entender Sass es como CSS con una caja de herramientas. Escribes archivos .scss o .sass utilizando las características de Sass, los pasas por un compilador y obtienes archivos .css planos que el navegador puede cargar. No hay coste de ejecución (runtime). Toda la potencia reside enteramente en tu flujo de trabajo de desarrollo.
Sass vs CSS: ¿qué cambia?
CSS puro es un lenguaje declarativo: describes cómo deben verse los elementos, pero no puedes crear abstracciones, reutilizar lógica ni organizar el código más allá de separar el contenido en archivos distintos. Sass soluciona cada una de esas limitaciones:
| Capacidad | CSS puro | Sass |
|---|---|---|
| Variables | Propiedades personalizadas (--var) |
$variable con alcance (scoping) completo |
| Anidamiento | Básico (ya disponible en CSS) | Maduro, con selectores de padre (&) |
| Reutilización | Copiar y pegar o clases de utilidad | Mixins, funciones y extends |
| Organización | Solo @import |
@use, @forward, partials |
| Lógica | Ninguna | @if, @each, @for, @while |
| Matemáticas | Solo calc() |
Aritmética completa en cualquier valor |
| Colores | Valores fijos | lighten, darken, mix y más |
Sintaxis de Sass vs SCSS
Sass soporta dos sintaxis:
SCSS (.scss) — la más común. Utiliza llaves y puntos y coma, exactamente igual que CSS. Cualquier archivo CSS válido es automáticamente un archivo SCSS válido. Esto hace que su adopción sea sencilla:
/* style.scss */
$primary: #3498db;
.button {
background: $primary;
color: white;
&:hover {
background: darken($primary, 10%);
}
}
Sintaxis indentada (.sass) — la original. Utiliza la indentación y saltos de línea en lugar de llaves y puntos y coma, lo que la hace más concisa pero menos familiar:
/* style.sass */
$primary: #3498db
.button
background: $primary
color: white
&:hover
background: darken($primary, 10%)
SCSS es la sintaxis que encontrarás en prácticamente cualquier proyecto moderno. A menos que tengas una razón específica para elegir Sass indentado, utiliza .scss.
Por qué existe Sass
Sass se convirtió en el estándar de la industria porque resuelve problemas reales. Estos son los problemas principales que soluciona:
Repetición. Sin variables, cambiar un solo color implica hacer un “Buscar y Reemplazar” en cada archivo. Las variables de Sass te permiten cambiar un valor una sola vez y actualizarlo en todas partes.
Estructura plana. Los componentes profundamente anidados producen selectores largos y repetitivos como .card .card-header .card-title. El anidamiento de Sass refleja la jerarquía de HTML en tus estilos.
Falta de reutilización. CSS no tiene el concepto de un bloque de estilos reutilizable. Un componente de botón con 10 variantes significaría 10 bloques casi idénticos. Los mixins y extends de Sass eliminan esa duplicación.
Ausencia de lógica. Generar una paleta de colores, alternar colores de filas o crear breakpoints responsivos a partir de una lista requiere herramientas externas. Sass te ofrece bucles y condicionales directamente en la hoja de estilos.
Organización. Importar docenas de archivos CSS con @import crea un espacio de nombres global plano donde los nombres inevitablemente colisionan. Los módulos de Sass (@use, @forward) solucionan esto mediante el uso de namespaces.
Variables
Las variables son la característica de Sass más sencilla y con mayor impacto. Una variable almacena un valor que puedes reutilizar en toda tu hoja de estilos:
/* style.scss */
$primary: #3498db;
$secondary: #2ecc71;
$font-stack: 'Helvetica Neue', Arial, sans-serif;
$spacing-unit: 8px;
body {
font-family: $font-stack;
}
.container {
padding: $spacing-unit * 3;
}
.btn-primary {
background: $primary;
color: white;
}
Cambia $primary una sola vez al principio y cada elemento que lo referencie se actualizará automáticamente. Las variables de Sass son constantes en tiempo de compilación; no existen en el CSS resultante. Esto es diferente de las propiedades personalizadas de CSS (--var), que residen en el navegador en tiempo de ejecución. Utiliza variables de Sass para valores que no necesiten cambiar dinámicamente.
Las variables tienen alcance (scope). Una variable declarada dentro de una regla o mixin es local a ese bloque. Utiliza !global para sobrescribir una variable global desde un alcance local, aunque esto rara vez es necesario:
/* style.scss */
$color: red; // global
.box {
$color: blue; // local — only exists inside .box
color: $color;
}
// $color is still red here
Anidamiento (Nesting)
El anidamiento te permite escribir selectores hijos dentro de su padre, reflejando la estructura de HTML y manteniendo los estilos relacionados agrupados:
/* style.scss */
.nav {
display: flex;
gap: $spacing-unit * 2;
&__item {
padding: $spacing-unit;
&--active {
font-weight: bold;
border-bottom: 2px solid $primary;
}
&:hover {
background: rgba($primary, 0.1);
}
}
&__logo {
margin-right: auto;
}
}
Esto se compila a:
/* compiled.css */
.nav { display: flex; gap: 16px; }
.nav__item { padding: 8px; }
.nav__item--active { font-weight: bold; border-bottom: 2px solid #3498db; }
.nav__item:hover { background: rgba(52, 152, 219, 0.1); }
.nav__logo { margin-right: auto; }
El selector padre & es esencial. Hace referencia al selector padre, por lo que &__item dentro de .nav se convierte en .nav__item. Sin &, Sass trata el ampersand como el contexto del padre. También puedes usar & para pseudo-clases y pseudo-elementos en lugar de anidarlos como bloques separados.
Aunque CSS nativo ya soporta el anidamiento básico, el anidamiento de Sass es más maduro: soporta & para referencias arbitrarias al padre, funciona en cualquier lugar y ha sido probado en producción durante más de una década.
Partials e imports
Los partials son archivos Sass diseñados para ser importados, no para compilarse por sí solos. Nómbralos con un guion bajo al principio — _variables.scss, _buttons.scss, _mixins.scss — y Sass los omitirá durante la compilación directa:
// _variables.scss
$primary: #3498db;
$spacing: 8px;
$font-stack: 'Helvetica Neue', Arial, sans-serif;
// _buttons.scss
@use 'variables' as *;
.button {
padding: $spacing * 2;
background: $primary;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
// main.scss
@use 'variables' as *;
@use 'buttons';
@use 'layout';
@use 'typography';
La regla @use importa un archivo como un módulo. Luego, puedes acceder a sus miembros a través de un namespace o usar as * para traer todo al scope actual. Esto mantiene tu namespace global limpio y evita colisiones de nombres entre archivos.
Módulos: @use y @forward
La regla @import está obsoleta. Combinaba todos los archivos en un único scope global, lo que significaba que un $primary en un archivo podía sobrescribir silenciosamente un $primary en otro. Los reemplazos modernos son @use y @forward.
@use
@use importa un módulo y le asigna un namespace:
/* style.scss */
@use 'variables';
.button {
background: variables.$primary;
padding: variables.$spacing * 2;
}
Puedes crear un alias para el namespace o traer todos los miembros al scope:
/* style.scss */
@use 'variables' as v;
@use 'variables' as *; // no namespace needed
@forward
@forward re-exporta los miembros de un módulo para que los archivos que importen el módulo actual tengan acceso a ellos. Se utiliza para crear barrel files: un único punto de entrada que expone múltiples módulos:
// _index.scss
@forward 'variables';
@forward 'mixins';
@forward 'functions';
// main.scss
@use 'index' as *; // gets everything from variables, mixins and functions
Usa @forward con show y hide para controlar qué miembros se re-exportan:
/* style.scss */
@forward 'variables' show $primary, $secondary;
@forward 'mixins' hide $internal-helper;
Mixins
Los mixins son bloques de estilos reutilizables que puedes parametrizar e incluir en cualquier lugar. Piensa en ellos como funciones que generan declaraciones CSS:
/* mixins.scss */
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
@mixin respond-to($breakpoint) {
@if $breakpoint == 'tablet' {
@media (min-width: 768px) { @content; }
} @else if $breakpoint == 'desktop' {
@media (min-width: 1024px) { @content; }
}
}
.hero {
@include flex-center;
min-height: 100vh;
@include respond-to('desktop') {
min-height: 80vh;
}
}
.card {
@include flex-center;
padding: 1rem;
}
Los mixins pueden tener parámetros por defecto, aceptar cualquier número de argumentos y utilizar @content para aceptar un bloque de estilos desde el llamador. Son el mecanismo de abstracción principal en Sass; los sistemas de diseño, los helpers responsivos y las capas de compatibilidad entre navegadores se construyen basándose en mixins.
Funciones
Las funciones de Sass computan y devuelven un valor. Son similares a los mixins, pero en lugar de generar CSS, producen un valor que puedes asignar:
/* functions.scss */
@function spacing($n) {
@return $n * 8px;
}
@function shade($color, $percentage) {
@return mix(black, $color, $percentage);
}
.hero {
padding: spacing(4); // 32px
background: shade(#3498db, 20%);
}
.sidebar {
padding: spacing(2); // 16px
}
Sass incluye muchas funciones integradas para colores (lighten, darken, saturate, adjust-hue), cadenas de texto (str-length, str-insert), matemáticas (abs, min, max, round) y listas (length, nth, append, index). También puedes escribir las tuyas propias para implementar lógica específica de tu proyecto.
Extends y herencia
La regla @extend permite que un selector herede los estilos de otro. Sass fusiona los dos selectores en una sola regla en el CSS resultante:
/* style.scss */
%message {
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
.success {
@extend %message;
background: #d4edda;
color: #155724;
}
.error {
@extend %message;
background: #f8d7da;
color: #721c24;
}
.warning {
@extend %message;
background: #fff3cd;
color: #856404;
}
Se compila a:
/* compiled.css */
.success, .error, .warning {
padding: 1rem;
border-radius: 4px;
margin-bottom: 1rem;
}
.success { background: #d4edda; color: #155724; }
.error { background: #f8d7da; color: #721c24; }
.warning { background: #fff3cd; color: #856404; }
Los placeholders (selectores que comienzan con %) no se exportan al CSS por sí solos; solo aparecen cuando son extendidos. Esto evita que haya reglas vacías en el resultado compilado.
Usa @extend para patrones estructurales compartidos. Para cualquier cosa que requiera parámetros, usa un mixin en su lugar, ya que @extend no puede aceptar argumentos.
Operadores
Sass soporta los operadores aritméticos estándar para trabajar con números:
/* style.scss */
$column-count: 12;
$gutter: 24px;
$gap: $gutter / 2; // 12px
$base: 16px;
$heading-1: $base * 2; // 32px
$heading-2: $base * 1.5; // 24px
$full-width: 100%;
$sidebar: $full-width / 3; // 33.333%
// Remainder
$remainder: 17 % 5; // 2
Sass también soporta la interpolación de strings, operadores de comparación y operadores booleanos:
/* style.scss */
$primary: #3498db;
$dark: darken($primary, 20%);
$is-dark: true;
@mixin theme-bg {
@if $is-dark {
background: $dark;
} @else {
background: $primary;
}
}
Ten en cuenta que la división (/) ahora se trata como una fracción de CSS en algunos contextos (por ejemplo, font: 16px/1.5). Envuelve las divisiones en math.div() para evitar ambigüedades, o utiliza calc() para divisiones dinámicas.
Flujo de control
Sass incluye condicionales y bucles que generan CSS en tiempo de compilación:
@if / @else
/* style.scss */
$theme: 'light';
@mixin theme-bg {
@if $theme == 'light' {
background: white;
color: black;
} @else if $theme == 'dark' {
background: #1a1a2e;
color: white;
} @else {
background: #f0f0f0;
color: #333;
}
}
@each
Itera sobre una lista o un mapa:
/* style.scss */
$colors: (
primary: #3498db,
secondary: #2ecc71,
danger: #e74c3c,
);
@each $name, $color in $colors {
.text-#{$name} {
color: $color;
}
.bg-#{$name} {
background: $color;
}
}
@for
Genera un rango de selectores:
/* style.scss */
@for $i from 1 through 12 {
.col-#{$i} {
width: ($i / 12) * 100%;
}
}
@for $i from 1 through 5 {
.mt-#{$i} {
margin-top: $i * 8px;
}
}
@while
Ejecuta un bucle mientras una condición sea verdadera:
/* style.scss */
$columns: 12;
$i: $columns;
@while $i > 0 {
.col-#{$i} {
width: ($i / $columns) * 100%;
}
$i: $i - 1;
}
Mapas y listas
Sass cuenta con estructuras de datos de primera clase para colecciones.
Las listas están ordenadas y separadas por comas o espacios:
/* style.scss */
$breakpoints: 480px, 768px, 1024px, 1280px;
@each $bp in $breakpoints {
@media (min-width: $bp) {
.container {
max-width: $bp;
}
}
}
// Lists can be nested
$margins: (8px, 16px, 24px, 32px);
Los mapas son pares de clave-valor, similares a los objetos o diccionarios:
/* style.scss */
$theme: (
primary: #3498db,
secondary: #2ecc71,
bg: white,
text: #333,
);
@each $key, $value in $theme {
--color-#{$key}: #{$value};
}
Puedes acceder a los valores de un mapa con map-get, fusionarlos con map-merge, comprobar si existen con map-has-key e iterar con @each.
Funciones integradas de Sass
Sass incluye una biblioteca estándar muy completa:
/* style.scss */
// Colour manipulation
$primary: #3498db;
.lighter { color: lighten($primary, 20%); }
.darker { color: darken($primary, 15%); }
.desaturated { color: desaturate($primary, 30%); }
.hue-shifted { color: adjust-hue($primary, 30deg); }
// Colour functions
$alpha: rgba($primary, 0.5); // semi-transparent
$contrast: contrast-color($primary); // contrast-safe colour
// Maths
$rounded: round(3.14); // 3
$limited: clamp(1, 10, 5); // 5
$half: math.div(100%, 2); // 50%
// Strings
$name: to-upper-case('sass'); // SASS
$length: str-length('hello'); // 5
$joined: str-insert('hello', ' world', 6); // 'hello world'
// Lists
$items: append(1px, 2px, 3px, 4px);
$first: nth($items, 1); // 1px
$count: length($items); // 4
Estas funciones están disponibles globalmente en SCSS y a través de @use 'sass:color', @use 'sass:math', @use 'sass:string', @use 'sass:list' y @use 'sass:map'.
Cómo usar Sass
Dart Sass
Dart Sass es la implementación canónica y la única de Sass que cuenta con mantenimiento activo. Instálalo con:
npm install sass
Luego, compila los archivos directamente:
npx sass src/styles.scss dist/styles.css
Integración con herramientas de construcción
En la mayoría de los proyectos modernos, Sass es gestionado por tu bundler. Vite, webpack, Parcel y esbuild soportan Sass de forma nativa:
Vite — solo instala sass e importa archivos .scss:
import './styles.scss';
webpack — añade sass-loader:
module.exports = {
module: { rules: [{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }] }
};
Compilación mediante CLI
# Watch mode — recompile on every save
npx sass --watch src:dist
# One compile
npx sass src/styles.scss dist/styles.css
# Output compressed CSS
npx sass --style=compressed src/styles.scss dist/styles.css
Mejores prácticas
- Usa la sintaxis SCSS. Es compatible con CSS, ampliamente adoptada y mucho más legible que la sintaxis indentada.
- Usa
@usey@forward, nunca@import. El sistema de importación está obsoleta y provoca la contaminación del scope global. - Organiza mediante partials. Una responsabilidad por archivo:
_variables.scss,_mixins.scss,_buttons.scss,_layout.scss. - Crea namespaces para tus módulos. Usa
@use 'module' as varo deja que el namespace por defecto (module.$var) aclare de dónde provienen los valores. - Usa placeholders para patrones compartidos. Los selectores
%placeholdersolo generan CSS cuando se extienden, manteniendo el resultado final ligero. - Escribe mixins parametrizados en lugar de extends. Los mixins son más flexibles y producen un CSS explícito y predecible.
- Mantén la lógica de negocio fuera de las hojas de estilo. Las funciones y bucles de Sass pertenecen a tu pipeline de build, no a la lógica de tus componentes.
- Aplica linting a tu Sass. Usa
stylelintcon un plugin de Sass para detectar deprecaciones y aplicar convenciones. - Genera CSS comprimido para producción. Usa
--style=compressedo deja que tu bundler lo minifique. - Evita los selectores profundamente anidados. Dos o tres niveles son suficientes. Un anidamiento mayor suele indicar un problema de estructura o de nomenclatura.