Listado

@use y @forward en SASS

En los últimos años los preprocesadores de CSS se han hecho muy populares porque permiten escribir CSS de forma programática. Esto ha supuesto un importante salto adelante en flexibilidad y potencia a la hora de declarar estilos, siendo Sass el más conocido y usado.

Autor/a

Fecha de publicación

17/6/2022

Compartir

Twitter

LinkedIn

Y es que, aunque actualmente existen muchas otras formas de estilar nuestras aplicaciones web, como CSS-in-JS en alguno de sus múltiples sabores, PostCSS o CSS modules, el uso de SASS sigue estando muy extendido, como revela el último The State of CSS 2021, y, por tanto, sigue siendo una herramienta con largo recorrido.

Module System

En 2019 Sass anunció Module System, un cambio notable en el core de su herramienta que dejaría atrás el uso de @import y algunas funciones globales. También anunció que la implementación llamada Dart Sass (basada en JavaScript y en la que se trabajaba desde 2016) ya soportaba el nuevo sistema de módulos, por lo que desde la organización empezaron a fomentar su uso por delante de LibSass y RubySass.

A pesar de existir retrocompatibilidad y de que podían cohexisitir ambos enfoques, tras un período de transición -para dar tiempo a los autores a realizar este cambio-, se tomó la decisión de abandonar definitivamente @import y los viejos módulos internos de SASS a más tardar el 1 de octubre de 2022.

Por entonces, LibSass estaba muy extendida (como dependencia de node-sass) pero no soportaba totalmente el nuevo sistema de módulos y, además, acabaría deprecada, por lo que el cambio acabaría siendo forzado.

¿Y cómo me afecta esto?

Pues depende. Significa que vamos a tener un montón de legacy code que tendríamos que migrar, algo que puede hacerse siguiendo esta guía de migración. Pero, si algo está funcionando, ¿por qué cambiarlo? Pues porque también significa que cuando uses SASS en tus nuevos desarrollos, tendrás que utilizar el nuevo sistema de módulos y, por tanto, tendrás que conocer las nuevas reglas.

@use y @forward

Lo más destacable de esta versión es la aparición de estas dos nuevas reglas, que vienen para reemplazar a @import y que van a eliminar el ámbito global en el que vivían las utilidades.

Hasta ahora, incluíamos en un única hoja de estilos (en un índice) el resto de ficheros parciales que estilaban otros componentes o partes de la aplicación, así como ciertas utilidades; variables, mixins, placeholders y funciones, a las que todos esos parciales tenían acceso y podían utilizar. Pero con el nuevo sistema de módulos, cuando un parcial quiera acceder a alguna utilidad tendrá que importarla explícitamente, de manera que tendremos más control y de un simple vistazo sabremos qué código que no pertenece a ese parcial se está utilizando y de dónde viene, algo muy parecido a los import de JavaScript.

Pero no sólo eso, existen otras muchas ventajas.

Beneficios

  • Localización. Es mucho más fácil saber qué se está utilizando en cada hoja de estilos y de dónde viene al tener que estar declarado explícitamente al principio del archivo.
  • Desaparece el ámbito global. Al no existir un espacio virtual común para nuestras variables, mixins y funciones, se evitarán colisiones por nombres repetidos entre nuestro código y el de terceros. Así, por ejemplo, podríamos tener un mixin llamado row que existiese también con el mismo nombre en una librería de un tercero que estemos usando.
  • Encapsulación. Los archivos importados se encapsulan usando un namespace lo que evitará colisiones dentro del mismo archivo.
  • Evitar duplicaciones. Con @import podías importar el mismo archivo tantas veces como quisieras, más por error que a propósito, afectando el CSS resultante, pero con @use y @forward tenemos protección frente a estos despistes.
  • Desambiguación. Al dejar de utilizarse @import desaparece también la ambigüedad que existía, ya que @import es una regla de CSS.
  • Privacidad. Podemos declarar miembros privados que no podrán ser utilizados desde fuera de ese archivo o, al importar un archivo, podemos declarar cuáles son exactamente los queremos importar o cuáles no queremos que lo hagan.
  • Flexibilidad con librerías de terceros. Podemos configurar librerías de terceros sin tener que sobreescribirlas, un punto también interesante como autores de una librería.

👉 Como “miembros” nos referimos a variables, funciones y mixins.

@use

@use "theme";

.text {
	color: theme.$primary-color;
}

Se declara al principio del archivo en el que se quiere tener acceso a esos miembros (variables, mixins y funciones) para poder utilizarlos.

Por defecto están encapsulados con el nombre del fichero, de modo que si queremos acceder a la variable $primary-color de theme.scss tendremos que hacerlo como theme.$primay-color. Esto nos permite usar en el mismo fichero dos o más $primary-color si vienen de archivos diferentes.

Además, podemos renombrar los namespaces usando as.

@use "theme" as defaultTheme;
@use "../3rd-party-library/theme" as externalTheme;

.box {
	color: defaultTheme.$primary-color;
	background-color: externalTheme.$primary-color;
}

También podemos eliminar el namespace usando ***** , aunque, en este caso, si hubiese coincidencias entre variables de diferentes importaciones SASS lanzaría un error.

@use "theme" as *;
@use "../3rd-party-library/theme" as *;

.box {
  // desde theme
  color: $primary-color;

  // desde 3rd-party-library/theme
  background-color: $primary-color;
}

Además, en la declaración de los miembros, podemos hacerlos privados. Es decir, solo para uso interno y que no se tenga acceso a éste desde fuera, prefijándolo con - o _.

// _palette.scss

// variable accesible
$primary-color: '#282828';

// mixin no accesible desde el exterior
@mixin _reset-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

@forward

Sirve para traer a un fichero el contenido de otro. Por ejemplo, el índice en el que importamos parciales a través de @import.

Como con @use, tenemos protección ante duplicidad de código si tratamos de llamarlo dos veces pero, a diferencia de éste, @forward no añade namespaces.

// Ajustes generales
@forward "base/reset";
@forward "base/reset"; // no duplicamos código
@forward "base/common";

// Componentes comunes
@forward "../components/";

Otra similitud con @use es la posibilidad de manejar la privacidad de los miembros, pero en este caso se indica en el momento de utilizar @forward utilizando claúsulas para declarar qué queremos importar o cuáles queremos excluir, usando show o hide.

// importando SOLO la variable $hero-color
@forward "hero" show $hero-color;

// importando TODO menos el mixin triangle()
@forward "utils" hide triangle; 

Módulos internos (built-in)

Algunos de los módulos internos y utilidades de SASS han cambiado, porque son nuevos, o han sido renombrado o eliminados. Por eso, no dejes de consultarlos en la documentación oficial. En cualquier caso, lo más importante es que ahora tendrás que acceder a los módulos de forma explícita con @use y que podrás renombrarlos.

@use "sass:math" as builtInSassMathModule;
@use "sass:color";

@use "theme";

body {
  &::before {
    content: builtInSassMathModule.random();
		color: color.alpha(theme.$color);
  }
}

Configuración de librerías de terceros

Con @use podemos configurar librerías de terceros sin tener que sobreescribir sus valores, usando with en el momento de la importación.

$custom-breakpoints: (
  mobile: 375px,
  tablet-small: 640px,
  tablet: 780px,
  tablet-large: 920px,
  desktop: 1180px,
  wide: 1400px,
);

$custom-show-breakpoints: (mobile, tablet, desktop, wide);

@forward "../node_modules/sass-mq/mq" with (
  $breakpoints: $custom-breakpoints,
  $show-breakpoints: $custom-show-breakpoints
);

Conclusiones

A pesar de que el sistema de módulos traía muchas ventajas, no se produjo una transición masiva y todavía sigue habiendo mucho código que usa @import. Esto se debe probablemente a que se juntaron varios factores al mismo tiempo, como por ejemplo:

  • El auge del shadow-dom y la posibilidad de encapsular estilos en componentes reutilizables
  • CSS-in-JS- Styled-components
  • Styled-components
  • Emotion
  • JSS
  • CSS modules
  • Tailwind (y otras librerías de utilidades)

Así que, debido al amplio abanico de posibilidades que se iba abriendo y a que LibSass seguía disponible y no suponía ningún cambio, siguió siendo muy popular (como muestra npm trends). Pero con el anuncio de que LibSass desaparecerá y el cambio será obligatorio para los nuevos desarrollos, si queremos seguir usando SASS hay que empezar a acoger el cambio y no aplazar más lo inevitable, por eso os dejamos el enlace a un repositorio con una estructura básica scratcheada y con algunos comentarios para que podáis probarlo 🙂 .

Relacionados

Cascade Layers

Cascade Layers es una manera de organizar los estilos de nuestras aplicaciones separándolos por capas que se apilan unas sobre otras para componer con más control.

12/6/2023

Charlamos sobre sistemas de diseño con Aarón García

A estas alturas nadie cuestiona ya los beneficios que tiene, de forma general, contar con un sistema de diseño (DS, Design System) para la creación de productos digitales. Para profundizar un poco más sobre este tema y descubrir cómo se están implementando en otros sitios, hemos tenido ocasión de charlar recientemente con Aarón García, Lead Design System Engineer en New Relic.

22/3/2023

Button Text