Período de prueba de CSS

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

Adam Argyle
Adam Argyle

Antes de anidar, cada selector debía declararse de manera explícita, por separado uno del otro. Esto genera repeticiones, la carga masiva de hojas de estilo y una experiencia de creación dispersa.

Antes
.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

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

Después de anidarlos, se pueden continuar con los selectores y se pueden agrupar las reglas de diseño relacionadas con ellos.

Después
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Pruébalo en el navegador.

El Nesting ayuda a los desarrolladores, ya que reduce la necesidad de repetir selectores, a la vez que ubica en conjunto las reglas de diseño para los elementos relacionados. También puede ayudar a que los estilos coincidan con el código 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 archivos para instancias de selector relacionadas.

La anidación puede ser útil para lo siguiente: - Organización - Reducción del tamaño de los archivos - Refactorización

El Nesting está disponible a partir de Chrome 112 y también para probarlo en la Versión preliminar técnica de Safari 162.

Comienza a usar el período de Nesting de CSS

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

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

Dentro de la zona de pruebas hay círculos, triángulos y cuadrados. Algunos son pequeños, medianos o grandes. Otros son azules, rosados o púrpuras. Todos están dentro del elemento que contiene .demo. La siguiente es una vista previa de los elementos HTML que se segmentarán.

<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 elementos que sean secundarios de elementos con una clase .parent.

De manera alternativa, este ejemplo podría escribirse 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.

Selección de los círculos

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

Sin anidar, CSS en la actualidad:

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

Con el anidamiento, existen dos maneras 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);
  }
}

Como resultado, todos los elementos dentro de .demo con una clase .circle se difuminan y son casi invisibles:

La cuadrícula colorida de formas ya no tiene círculos;
    son muy débiles 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 grupos.

Sin anidar, actualmente el CSS tiene dos maneras:

.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 anidación, estas son dos maneras válidas:

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

o

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

Resultado, solo los elementos .circle permanecen dentro de .demo:

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

Selección de triángulos y círculos grandes

Esta tarea requiere un selector compuesto, en el que los elementos deben tener ambas clases para poder seleccionarse.

Sin anidar, CSS en la actualidad:

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

o

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

Con anidación, estas son dos maneras 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:

La cuadrícula colorida solo tiene formas pequeñas y medianas visibles.
Probar una demostración
Sugerencia profesional con anidación y selectores compuestos

El símbolo & es tu amigo, ya que muestra explícitamente cómo adjuntar 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. Esto se debe a que, sin & para especificar el resultado deseado de .lg.triangle, .lg.circle compuesto, el resultado real sería .lg .triangle, .lg .circle; selectores descendientes.

Seleccionar todas las formas, excepto las rosas

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

Sin anidar, CSS en la actualidad:

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

Con anidación, estas son dos maneras 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 rosas 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 quieres orientar .demo con el selector :not(). Para ello, se requiere &:

.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 anidamiento

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

En los siguientes ejemplos, se presentará brevemente una función de anidamiento de CSS para ayudarte a comprender la amplitud de funciones que incluye.

Período de prueba de @media

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

Para mayor comodidad de la sintaxis, si la consulta de medios 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 se puede usar & explícitamente:

.card {
  font-size: 1rem;

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

En este ejemplo, se muestra la sintaxis expandida con & y se orienta a las tarjetas .large para demostrar que las funciones de anidación adicionales continúan funcionando.

Obtén más información sobre cómo anidar @rules.

Anidar en cualquier lugar

Todos los ejemplos hasta este punto continuaron o se adjuntaron a un contexto anterior. Puedes cambiar o reorganizar completamente el contexto si es necesario.

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

El símbolo & representa una referencia a un objeto selector (no una cadena) y se puede colocar en cualquier lugar del 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 es útil poder repetir un contexto de selección.

Ejemplos de anidamiento no válidos

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

Anidación y concatenación

Muchas convenciones de nomenclatura de clases CSS cuentan con que el anidamiento puede 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 a objetos.

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

Puede encontrar una explicación más detallada en las especificaciones.

Ejemplo de anidamiento complejo

Anidación en listas de selectores y :is()

Considera el siguiente bloque CSS anidado:

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

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

Para que la intent de anidación funcione, el navegador unirá cualquier lista de selección que no sea la más anidada con :is(). Esta unión mantiene la agrupación de la lista del selector dentro de cualquier contexto creado. 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 del paréntesis. Así es como :is() siempre funciona, pero puede sorprenderte cuando se usa la sintaxis de anidamiento, ya que no es exactamente lo que se creó. En resumen, anidar con IDs y listas de selectores puede generar selectores de especificidad muy alta.

Para recapitular claramente el ejemplo complicado, el bloque de anidamiento 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 que adviertan que cuando anidan dentro de una lista de selector que usa un selector de ID, la especificidad de todos los elementos anidados dentro de esa lista de selectores será alta.

Cómo mezclar anidamiento y declaraciones

Considera el siguiente bloque CSS anidado:

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

El color de los elementos .card será blue.

Cualquier declaración de diseño entremezclado se eleva a la parte superior, como si se hubiera creado antes de que se produjera la anidación. Puedes encontrar más detalles en las especificaciones.

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

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

De hecho, se recomienda unir cualquier diseño que siga la anidación con un &.

.card {
  color: green;

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

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

Detección de funciones

Existen dos maneras excelentes de detectar el anidamiento de CSS: usa el anidamiento o @supports para verificar la capacidad de análisis del selector de anidación.

Captura de pantalla de la demostración de Codepen de Bramus en la que se pregunta si tu navegador es compatible con la anidación de CSS. Debajo de esa pregunta, hay un cuadro verde que indica apoyo.

Uso de la anidación:

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 que muestra esta estrategia.

Depuración con Herramientas para desarrolladores de Chrome

La compatibilidad actual con la anidación en Herramientas para desarrolladores es mínima. Actualmente, encontrarás que los diseños se representan en el panel Estilos como se espera, pero aún no se admite el seguimiento del anidamiento ni el contexto completo del selector. Tenemos un diseño y planes para que sea transparente y claro.

Captura de pantalla de la sintaxis de anidamiento de las Herramientas para desarrolladores de Chrome.

Chrome 113 planea tener compatibilidad adicional con la anidación de CSS. ¡No te pierdas las novedades!

El futuro

El Nesting de CSS solo está disponible en la versión 1. La versión 2 incorporará más sintaxis sintáctica y posiblemente menos reglas para memorizar. Existe mucha demanda para que el análisis de la anidación no sea limitado o tenga momentos complicados.

El anidamiento es una gran mejora del lenguaje CSS. Tiene implicaciones de creación en casi todos los aspectos arquitectónicos de CSS. Se debe explorar y comprender en profundidad y comprender este gran impacto antes de especificar la versión 2 de manera efectiva.

Para terminar, aquí hay una demostración que usa @scope, anidación y @layer juntos. ¡Es muy emocionante!

Una tarjeta clara sobre un fondo gris. Tiene un título y texto, algunos botones de acción y una imagen de estilo cyberpunk.