CSS Nesting: CSS anidado

Aunque actualmente no está soportado por los navegadores, existe una propuesta de anidamiento CSS para dar soporte a una característica que proporcionaría una mejor legibilidad al CSS nativo, por lo que en el futuro es muy probable que esté soportada y se pueda utilizar directamente.

La idea detrás del concepto CSS Nesting es la posibilidad de crear reglas CSS (bloques de código CSS) dentro de otras reglas CSS, anidando código y haciéndolo mucho más fácil de entender y mantener.

CSS Nesting

No obstante, si estamos utilizando PostCSS en nuestro proyecto, podemos utilizarla ya mismo traduciéndola a CSS nativo con esta herramienta, sin tener que esperar a que los navegadores la soporten, con alguno de los siguientes plugins:

Plugin Autor Descripción
postcss-nesting jonathanneal Anidamiento CSS basándose en el estándar oficial de CSS Nesting.
postcss-to-nest jonathanneal Transforma código CSS sin anidar en código CSS anidado. Útil para legacy.
postcss-nested postcss Anidamiento CSS basándose en como lo hace el preprocesador Sass.

Veremos más adelante como instalarlo y utilizarlo, pero vamos a explicar primero en que consiste el CSS Nesting (anidamiento CSS).

Anidamiento CSS (&)

Cuando escribimos CSS, tenemos que dominar y utilizar selectores CSS básicos y selectores CSS avanzados para seleccionar los elementos a los que queremos dar estilo y escribir nuestras reglas específicas. Con el CSS Nesting (anidamiento de CSS) no es que evitemos utilizarlos, sino que los utilizaremos menos porque usando el indentado (similar a como ocurre en Python) estaremos creando selectores, sólo que de una forma «más lógica para humanos».

El CSS Nesting se basa en la posibilidad de incluir bloques de CSS uno dentro de otro (algo que no es posible actualmente en CSS nativo), de modo que facilita la organización del código a medida que se lee. Se utilizará el carácter & para indicar que se sustituye por todo el selector padre que tengamos (en este ejemplo, .item, pero en casos con mayor anidamiento será más largo):

.item {
  padding: 10px;

  & .warning {
    background: red;
    color: white;
  }
}

Tenemos la clase .warning en el interior del bloque .item, por lo que eso implica que sólo se le dará estilo CSS a las clases .warning que estén dentro del elemento .item. Esto se traduce a CSS nativo de la siguiente forma:

.item {
  padding: 10px;
}

.item .warning {
  background: red;
  color: white;
}

Quizás con este ejemplo aún no se vea claramente la ventaja del anidamiento CSS, pero a medida que escribimos más código las ventajas se hacen evidentes. Si has trabajado con CSS durante algún tiempo, habrás comprobado que una de las cosas más complejas de CSS es mantener el código a medida que crece. En este apartado es donde brilla el anidamiento.

Grandes ventajas de utilizar CSS Nesting:

  • El primer nivel de anidamiento se puede usar como un «componente» o entidad.
  • Simplifica mucho los selectores CSS, haciéndolos más intuitivos (sobre todo para novatos).
  • Al indentar, el código se hace mucho más legible.
  • Al agrupar con comas y anidar conseguimos mucha más flexibilidad en menos código.
  • Buscar fragmentos de código es mucho más fácil (si somos organizados).

Compliquemos un poco más un código de ejemplo con anidamiento CSS:

.menu,
.sidebar {
  background: black;
  color: white;
  padding: 10px;

  & a {
    color: #333399;
    font-size: 1.25rem;
  }

  & .warning {
    background: red;
    color: white;
  }
}

.warning {
  color: red;
}

Observa que en este ejemplo tenemos los elementos a y las clases .warning tanto dentro de clases .menu como de clases .sidebar. Esto nos permitirá sustancialmente evitar repetir código. Este ejemplo se traduciría a CSS nativo como veremos a continuación:

.menu,
.sidebar {
  background: black;
  color: white;
  padding: 10px;
}

.menu a,
.sidebar a {
  color: #333399;
  font-size: 1.25rem;
}

.menu .warning,
.sidebar .warning {
  background: red;
  color: white;
}

.warning {
  color: red;
}

Como ves, es mucho más fácil de leer el ejemplo superior con anidamiento CSS que este último, donde a medida que crece es mucho menos legible.

Anidamiento sobre el padre

Un detalle interesante a tener en cuenta es que podemos anidar selectores sobre el padre, simplemente teniendo en cuenta si existe o no existe espacio entre el símbolo & de anidamiento.

.item {
  background: grey;

  &:hover {
    background: red;
  }
}

En este fragmento de código, el selector anidado &:hover realmente está haciendo referencia al selector .item:hover, es decir, cuando tenemos el ratón sobre el elemento .item.

Pero por otro lado, si añadieramos un espacio en el selector anidado & :hover estaríamos haciendo referencia a .item :hover, que tiene un matiz diferente al anterior: seleccionamos cuando tenemos el ratón sobre un elemento que está dentro de .item.

La regla @nest

En algunos casos, con el selector & podemos encontrar algunas limitaciones. Para ello, se introduce la regla @nest, mediante la cual podemos flexibilizar la forma de anidar selectores en nuestro código y hacerlo mucho más potente aún.

Por ejemplo, podemos utilizar el siguiente código para hacer referencia a cualquier mención del padre de primer nivel:

.item {
  background: grey;

  @nest .container & {
    background: green;
  }
}

La regla @nest nos permite avisar al navegador de que existe una referencia al selector padre en una parte del selector que estamos escribiendo (y que incluso puede ser posterior). Esto nos permitirá, por ejemplo, organizar grupos de código CSS donde aparezca cualquier mención a un determinado elemento.

El código equivalente en CSS nativo sería el siguiente:

.item {
  background: grey;
}

.container .item {
  background: green;
}

Como vemos, se ha reemplazado el & por el selector que está anidando, por lo que funciona correctamente.

Instalación de postcss-nesting

En nuestro caso, vamos a utilizar el plugin postcss-nesting de Jonathan Neal, ya que es el que sigue el estándar oficial y, el que nos interesa para que en el futuro nuestro código sea compatible con CSS nativo.

El primer paso sería instalar el paquete como una dependencia de desarrollo. Recuerda instalar el paquete postcss-cli si no tienes PostCSS en tu proyecto:

$ npm install --save-dev postcss-cli postcss-nesting

Una vez instalado, abrimos el fichero de configuración postcss.config.js en la carpeta raíz de nuestro proyecto. En él añadiremos postcss-nesting a la lista de plugins que estemos usando con postcss:

module.exports = {
  "plugins": {
    "postcss-nesting": true,
    "autoprefixer": true
  }
}

En este caso, observa que tenemos autoprefixer instalado también (aunque no es obligatorio para usar postcss-nesting) y lo hemos colocado después de postcss-nesting. El orden importa, ya que es el orden con el cuál PostCSS procesará los plugins y los aplicará.

Con esto tendríamos el plugin de PostCSS instalado. Ahora vamos a crear un fichero index.pcss para hacer un ejemplo y observar que funciona correctamente:

.item {
  background: grey;

  & .warning {
    background: red;
    animation: jump 10s linear;
  }

  @nest .container & {
    border: 2px solid red;
  }
}

Una vez guardado en src/css/index.pcss, podemos probar a ejecutar postcss y observa si aplica los cambios de los dos plugins instalados:

$ npx postcss src/css/index.pcss --no-map

Si todo está configurado correctamente, PostCSS debería sacar este código CSS, donde han sido aplicados los plugins:

.item {
  background: grey
}
.item .warning {
  background: red;
  -webkit-animation: jump 10s linear;
          animation: jump 10s linear;
}
.container .item {
    border: 2px solid red
}

El prefijo -webkit-animation es añadido por el plugin autoprefixer, que no tiene nada que ver con este capítulo. Si te interesa, puedes aprender sobre él en Plugins de PostCSS: Autoprefixer.

Ten en cuenta que el plugin postcss-nesting forma parte de un pack de plugins más grande llamado postcss-preset-env que veremos un poco más adelante, por lo que quizás te interese dicha aproximación.

Manz
Publicado por Manz

Docente, divulgador informático y freelance. Autor de Emezeta.com, es profesor en la Universidad de La Laguna y dirige el curso de Programación web FullStack y Diseño web FrontEnd de EOI en Tenerife (Canarias). En sus ratos libres, busca GIF de gatos en Internet.