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.
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).
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:
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.
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
.
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.
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 llamadopostcss-preset-env
que veremos un poco más adelante, por lo que quizás te interese dicha aproximación.