Período de prueba de CSS

Una de nuestras funciones favoritas del preprocesador de CSS ahora está integrada en el lenguaje: anidar reglas de estilo.

Adam Argyle
Adam Argyle

Antes del anidamiento, cada selector debía declararse de forma explícita, por separado. Esto genera repetición, gran cantidad de hojas de estilo y una experiencia de autoría desordenada.

Antes
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

Después de la anidada, los selectores se pueden continuar y las reglas de diseño relacionadas se pueden agrupar dentro de ellas.

Después
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Prueba esto en el navegador.

El anidamiento ayuda a los desarrolladores, ya que reduce la necesidad de repetir selectores y, al mismo tiempo, comparte las reglas de diseño de los elementos relacionados. También puede ayudar a que los estilos coincidan con el HTML al que se orientan. Si el componente .nesting del ejemplo anterior se quitó del proyecto, podrías borrar todo el grupo en lugar de buscar instancias de selectores relacionadas en los archivos.

El anidamiento puede ayudar con lo siguiente: - Organización - Reducción del tamaño del archivo - Refactorización

El anidamiento está disponible a partir de Chrome 112 y también se puede probar en la Versión preliminar técnica 162 de Safari.

Cómo comenzar a usar la anidación de CSS

En el resto de esta publicación,se usa la siguiente zona de pruebas para ayudarte a visualizar las selecciones. En este estado predeterminado, no se selecciona nada y todo es visible. Si seleccionas las diferentes formas y tamaños, puedes practicar la sintaxis y verla en acción.

Una cuadrícula colorida de círculos, triángulos y cuadrados pequeños y grandes.

Dentro de la zona de pruebas, hay círculos, triángulos y cuadrados. Algunos son pequeños, medianos o grandes. Otros son azules, rosas o morados. Todos están dentro del elemento .demo que los contiene. A continuación, se muestra una vista previa de los elementos HTML a los que segmentarás tus anuncios.

<div class="demo">
  <div class="sm triangle pink"></div>
  <div class="sm triangle blue"></div>
  <div class="square blue"></div>
  <div class="sm square pink"></div>
  <div class="sm square blue"></div>
  <div class="circle pink"></div>
  …
</div>

Ejemplos de anidación

El anidamiento de CSS te permite definir estilos para un elemento dentro del contexto de otro selector.

.parent {
  color: blue;

  .child {
    color: red;
  }
}

En este ejemplo, el selector de clase .child está anidado dentro del selector de clase .parent. Esto significa que el selector .child anidado solo se aplicará a los elementos que sean secundarios de elementos con una clase .parent.

Como alternativa, este ejemplo se podría escribir con el símbolo & para indicar de forma explícita dónde se debe colocar la clase superior.

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

Estos dos ejemplos son funcionalmente equivalentes, y el motivo por el que tienes opciones será más claro a medida que se exploren ejemplos más avanzados en este artículo.

Selecciona los círculos

En este primer ejemplo, la tarea es agregar estilos para atenuar y desenfocar solo los círculos dentro de la demostración.

Sin anidación, el CSS actual tiene las siguientes características:

.demo .circle {
  opacity: .25;
  filter: blur(25px);
}

Con anidamiento, hay dos formas válidas:

/* & is explicitly placed in front of .circle */
.demo {
  & .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

o

/* & + " " space is added for you */
.demo {
  .circle {
    opacity: .25;
    filter: blur(25px);
  }
}

El resultado: Todos los elementos dentro de .demo con una clase .circle están desenfocados y casi invisibles:

La cuadrícula colorida de formas ya no tiene círculos, están muy atenuados en el fondo.
Probar una demostración

Seleccionar cualquier triángulo y cuadrado

Esta tarea requiere seleccionar varios elementos anidados, también llamados selectores de grupo.

Sin anidamiento, CSS hoy en día, hay dos formas:

.demo .triangle,
.demo .square {
  opacity: .25;
  filter: blur(25px);
}

o con :is()

/* grouped with :is() */
.demo :is(.triangle, .square) {
  opacity: .25;
  filter: blur(25px);
}

Con anidamiento, estas son dos formas válidas:

.demo {
  & .triangle,
  & .square {
    opacity: .25;
    filter: blur(25px);
  }
}

o

.demo {
  .triangle, .square {
    opacity: .25;
    filter: blur(25px);
  }
}

El resultado: Solo quedan elementos .circle dentro de .demo:

La cuadrícula colorida de formas solo queda con círculos, y todas las demás formas son casi invisibles.
Probar una demostración

Cómo seleccionar triángulos y círculos grandes

Esta tarea requiere un selector compuesto, en el que los elementos deben tener ambas clases presentes para que se seleccionen.

Sin anidación, el CSS actual tiene las siguientes características:

.demo .lg.triangle,
.demo .lg.square {
  opacity: .25;
  filter: blur(25px);
}

o

.demo .lg:is(.triangle, .circle) {
  opacity: .25;
  filter: blur(25px);
}

Con anidamiento, estas son dos formas válidas:

.demo {
  .lg.triangle,
  .lg.circle {
    opacity: .25;
    filter: blur(25px);
  }
}

o

.demo {
  .lg {
    &.triangle,
    &.circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

El resultado: Todos los triángulos y círculos grandes están ocultos dentro de .demo:

En la cuadrícula colorida, solo se ven las formas pequeñas y medianas.
Probar una demostración
Sugerencia profesional con selectores compuestos y anidamiento

El símbolo & es tu amigo aquí, ya que muestra de forma explícita cómo unir selectores anidados. Consulta el siguiente ejemplo:

.demo {
  .lg {
    .triangle,
    .circle {
      opacity: .25;
      filter: blur(25px);
    }
  }
}

Si bien es una forma válida de anidar, los resultados no coincidirán con los elementos que podrías esperar. El motivo es que, sin & para especificar el resultado deseado de .lg.triangle, .lg.circle combinado, el resultado real sería .lg .triangle, .lg .circle; selectores descendientes.

Selecciona todas las formas excepto las rosas.

Esta tarea requiere una pseudoclase funcional de negación, en la que los elementos no deben tener el selector especificado.

Sin anidación, el CSS actual tiene las siguientes características:

.demo :not(.pink) {
  opacity: .25;
  filter: blur(25px);
}

Con anidamiento, estas son dos formas válidas:

.demo {
  :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

o

.demo {
  & :not(.pink) {
    opacity: .25;
    filter: blur(25px);
  }
}

El resultado: Todas las formas que no son de color rosa están ocultas dentro de .demo:

La cuadrícula colorida ahora es monocromática y solo muestra formas rosas.
Probar una demostración
Precisión y flexibilidad con &

Supongamos que deseas segmentar tus anuncios para .demo con el selector :not(). & es obligatorio para lo siguiente:

.demo {
  &:not() {
    ...
  }
}

Esto combina .demo y :not() en .demo:not(), a diferencia del ejemplo anterior, que necesitaba .demo :not(). Este recordatorio es muy importante cuando se desea anidar una interacción :hover.

.demo {
  &:hover {
    /* .demo:hover */
  }

  :hover {
    /* .demo :hover */
  }
}

Más ejemplos de anidación

La especificación del CSS para la anidación contiene más ejemplos. Si quieres obtener más información sobre la sintaxis a través de ejemplos, se abarca una amplia variedad de ejemplos válidos y no válidos.

En los siguientes ejemplos, se presentará brevemente una función de anidación de CSS para ayudarte a comprender la amplia variedad de capacidades que ofrece.

Anidación de @media

Puede ser muy molesto moverse a un área diferente de la hoja de estilo para encontrar condiciones de consulta de medios que modifiquen un selector y sus estilos. Esa distracción desaparece con la capacidad de anidar las condiciones dentro del contexto.

Para mayor comodidad de sintaxis, si la consulta de contenido multimedia anidada solo modifica los estilos para el contexto del selector actual, se puede usar una sintaxis mínima.

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    font-size: 1.25rem;
  }
}

También puedes usar & de forma explícita:

.card {
  font-size: 1rem;

  @media (width >= 1024px) {
    &.large {
      font-size: 1.25rem;
    }
  }
}

En este ejemplo, se muestra la sintaxis expandida con & y, al mismo tiempo, se segmentan tarjetas .large para demostrar que las funciones de anidación adicionales siguen funcionando.

Obtén más información sobre el anidaje de @rules.

Anidación en cualquier lugar

Todos los ejemplos hasta este punto continuaron o se agregaron a un contexto anterior. Si es necesario, puedes cambiar o reorganizar el contexto por completo.

.card {
  .featured & {
    /* .featured .card */
  }
}

El símbolo & representa una referencia a un objeto selector (no a una cadena) y se puede colocar en cualquier lugar de un selector anidado. Incluso se puede colocar varias veces:

.card {
  .featured & & & {
    /* .featured .card .card .card */
  }
}

Si bien este ejemplo parece un poco inútil, sin duda hay situaciones en las que es útil poder repetir un contexto de selector.

Ejemplos de anidación no válida

Hay algunas situaciones de sintaxis de anidación que no son válidas y pueden sorprenderte si has estado anidando en preprocesadores.

Anidación y concatenación

Muchas convenciones de nombres de clases de CSS dependen de que el anidamiento pueda concatenar o agregar selectores como si fueran cadenas. Esto no funciona en la anidación de CSS, ya que los selectores no son cadenas, sino referencias de objetos.

.card {
  &--header {
    /* is not equal to ".card--header" */
  }
}

Puedes encontrar una explicación más detallada en la especificación.

Ejemplo de anidación complicada

Anidamiento dentro de listas de selectores y :is()

Considera el siguiente bloque de CSS anidado:

.one, #two {
  .three {
    /* some styles */
  }
}

Este es el primer ejemplo que comienza con una lista de selectores y luego continúa anidándose. Los ejemplos anteriores solo terminaban con una lista de selectores. No hay nada no válido en este ejemplo de anidación, pero hay un detalle de implementación potencialmente complicado sobre la anidación dentro de listas de selectores, especialmente aquellas que incluyen un selector de ID.

Para que funcione el intent del anidamiento, el navegador unirá con :is() cualquier lista de selectores que no sea la más interna. Este unión mantiene la agrupación de la lista de selectores dentro de cualquier contexto creado por el autor. El efecto secundario de esta agrupación, :is(.one, #two), es que adopta la especificidad de la puntuación más alta dentro de los selectores dentro de los paréntesis. Esta es la forma en que :is() siempre funciona, pero puede ser una sorpresa cuando se usa la sintaxis de anidación porque no es exactamente lo que se escribió. El truco resumido: anidar con IDs y listas de selectores puede generar selectores de especificidad muy alta.

Para resumir claramente el ejemplo complicado, el bloque de anidación anterior se aplicará al documento de la siguiente manera:

:is(.one, #two) .three {
  /* some styles */
}

Presta atención o enseña a tus linters a advertir cuando se anidan dentro de una lista de selectores que usa un selector de ID. La especificidad de todo el anidamiento dentro de esa lista de selectores será alta.

Combinación de anidamiento y declaraciones

Considera el siguiente bloque de CSS anidado:

.card {
  color: green;
  & { color: blue; }
  color: red;
}

El color de los elementos .card será blue.

Todas las declaraciones de estilo intercaladas se elevan a la parte superior, como si se hubieran creado antes de que se produjera cualquier anidación. Puedes encontrar más detalles en la especificación.

Hay formas de evitarlo. A continuación, se unen los tres estilos de color en &, que mantiene el orden en cascada como el autor pudo haber deseado. El color de los elementos .card será rojo.

.card {
  color: green;
  & { color: blue; }
  & { color: red; }
}

De hecho, se recomienda unir todos los estilos que sigan anidando con un &.

.card {
  color: green;

  @media (prefers-color-scheme: dark) {
    color: lightgreen;
  }

  & {
    aspect-ratio: 4/3;
  }
}

Detección de atributos

Existen dos excelentes formas de detectar la anidación de CSS: usar la anidación o usar @supports para verificar si hay capacidad de análisis de selector de anidación.

Una captura de pantalla de la demostración de Codepen de Bramus, en la que se pregunta si tu navegador admite la anidación de CSS. Debajo de esa pregunta, hay un cuadro verde que indica que hay asistencia.

Usa anidamiento:

html {
  .has-nesting {
    display: block;
  }

  .no-nesting {
    display: none;
  }
}

Usa @supports de la siguiente manera:

@supports (selector(&)) {
  /* nesting parsing available */
}

Mi colega Bramus tiene un excelente Codepen en el que muestra esta estrategia.

Depuración con las Herramientas para desarrolladores de Chrome

La compatibilidad actual de DevTools con el anidamiento es mínima. Actualmente, verás que los estilos se representan en el panel Estilos como se espera, pero aún no se admite el seguimiento del anidamiento ni su contexto de selector completo. Tenemos un diseño y planes para hacer que esto sea transparente y claro.

Captura de pantalla de la sintaxis de anidación de Chrome DevTools.

Chrome 113 planea tener compatibilidad adicional con el anidamiento de CSS. ¡No te pierdas las novedades!

El futuro

La anidada de CSS solo está en la versión 1. La versión 2 incluirá más sintaxis enriquecida y, posiblemente, menos reglas para memorizar. Hay mucha demanda para que el análisis de anidación no sea limitado ni tenga momentos difíciles.

El anidamiento es una gran mejora en el lenguaje CSS. Tiene implicaciones de autoría para casi todos los aspectos arquitectónicos del CSS. Este gran impacto debe explorarse y comprenderse en profundidad antes de que se pueda especificar de manera eficaz la versión 2.

A modo de conclusión, esta es una demostración que usa @scope, anidamiento y @layer en conjunto. Es muy emocionante.

Una tarjeta clara sobre un fondo gris. La tarjeta tiene un título y texto,

  algunos botones de acción y una imagen de estilo ciberpunk.