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 anidación.

Adam Argyle
Adam Argyle

Antes de anidar, cada selector debía declararse explícitamente, independientemente del otro. Esto genera repetición, acciones masivas 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 la anidación, los selectores se pueden continuar y las reglas de estilo relacionadas con ellos se pueden agrupar.

Después
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Pruébalo en el navegador.

La anidación ayuda a los desarrolladores porque reduce la necesidad de repetir selectores y, al mismo tiempo, ubica las reglas de estilo para los elementos relacionados. También puede ayudar a que los estilos coincidan con el código HTML al que se segmentan. Si el componente .nesting del ejemplo anterior se quitara del proyecto, podrías borrar todo el grupo en lugar de buscar archivos para instancias de selector relacionadas.

La anidación puede ayudarte con lo siguiente: - Organización - Reducir el tamaño de los archivos - Refactorizar

El período de prueba está disponible en Chrome 112 y también se puede probar en la vista previa técnica de Safari 162.

Comienza a usar el período de prueba de CSS

En el resto de esta publicación,se usa 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 diferentes formas y tamaños, podrás practicar la sintaxis y ver cómo funciona.

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. Otras son azules, rosadas o púrpuras. Todos se encuentran dentro del elemento que contiene .demo. La siguiente es una vista previa de los elementos HTML para 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 en el 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.

Este ejemplo de forma alternativa se puede escribir con el símbolo & para indicar explícitamente dónde se debe colocar la clase superior.

.parent {
  color: blue;

  & .child {
    color: red;
  }
}

Estos dos ejemplos son equivalentes en términos de funcionalidad, y el motivo por el que tienes opciones será más claro a medida que se exploran ejemplos más avanzados en este artículo.

Cómo seleccionar 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 anidamiento, CSS actualmente tiene las siguientes características:

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

Con la anidación, 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 se difuminan y son casi invisibles:

La cuadrícula colorida de formas ya no tiene círculos; se ven 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 selector de grupos.

Sin anidamiento, CSS actualmente existen dos formas:

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

o bien con :is()

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

Con la anidación, estas son las dos formas válidas:

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

o

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

El resultado, solo los elementos .circle permanecen dentro de .demo:

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

Seleccionar triángulos y círculos grandes

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

Sin anidamiento, CSS actualmente 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 la anidación, estas son las 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:

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

El símbolo & es tu amigo aquí, ya que muestra de manera explícita 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 puedes esperar. El motivo es que, sin & para especificar el resultado deseado de .lg.triangle, .lg.circle compuesto, el resultado real sería .lg .triangle, .lg .circle; selectores subordinados.

Seleccionando 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 anidamiento, CSS actualmente tiene las siguientes características:

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

Con la anidación, estas son las 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 rosas se ocultan 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 .demo con el selector :not(). & es obligatorio para lo siguiente:

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

Esto suma .demo y :not() a .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 CSS para la anidación está repleta de más ejemplos. Si quieres obtener más información sobre la sintaxis a través de ejemplos, puedes consultar una amplia gama 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 variedad de capacidades que incluye.

Anidación de @media

Puede resultar muy molesto moverse a una área diferente de la hoja de estilo para encontrar las condiciones de la consulta de medios que modifican un selector y sus estilos. Esa distracción ya no existe con la capacidad de anidar las condiciones dentro del contexto.

Por conveniencia 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 & 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 orienta a las tarjetas .large para demostrar que siguen funcionando las funciones de anidación adicionales.

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

Anidamiento en cualquier lugar

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

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

El símbolo & representa una referencia a un objeto selector (no una string) 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 poder repetir un contexto de selector es útil.

Ejemplos de anidación no válidos

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 nomenclatura de las clases CSS cuentan con la posibilidad de anidar la posibilidad de concatenar o agregar selectores como si fueran strings. 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 las especificaciones.

Ejemplo de anidación complicada

Anidar en 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 anidando más. Los ejemplos anteriores solo habían terminado con una lista de selección. No hay nada no válido en este ejemplo de anidación, pero hay un detalle de implementación potencialmente engañoso sobre la anidación en listas de selectores, especialmente aquellos que incluyen un selector de ID.

Para que el intent del anidamiento funcione, el navegador unirá cualquier lista de selectores que no sea la lista de anidación más interna con :is(). Esta unión mantiene la agrupación de la lista de selectores dentro de los contextos de 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 entre paréntesis. Así es como siempre funciona :is(), pero puede resultar una sorpresa cuando se usa la sintaxis de anidación, ya que no es exactamente lo que se creó. El truco se resume: anidar con ID y listas de selectores puede generar selectores de especificidad muy alto.

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 enséñales a los linters a que adviertan cuando se anidan dentro de una lista de selectores que usa un selector de ID, la especificidad de todos los anidamientos dentro de esa lista de selectores será alta.

Combinación de anidación y declaraciones

Considera el siguiente bloque de CSS anidado:

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

El color de los elementos .card será blue.

Las declaraciones de estilo entremezcladas se elevan a la parte superior, como si se hubieran creado antes de que ocurriera cualquier anidación. Puedes encontrar más detalles en las especificaciones.

Hay formas de resolverlo. A continuación, se unen los tres estilos de color en &, lo que mantiene el orden de cascada como lo pretendía el autor. El color de los elementos .card será rojo.

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

De hecho, te recomendamos unir cualquier estilo que siga el anidamiento con un &.

.card {
  color: green;

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

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

Detección de atributos

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

Captura de pantalla de la demostración de Codepen de Bramus en la que se pregunta si tu navegador admite el anidamiento de CSS. Debajo de esa pregunta, aparece un recuadro verde que indica apoyo.

Con el 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 una excelente CodePen que muestra esta estrategia.

Depuración con Herramientas para desarrolladores de Chrome

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

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

Chrome 113 planea tener compatibilidad adicional para el anidamiento de CSS. No te pierdas ninguna novedad.

El futuro

El anidamiento de CSS solo está en la versión 1. La versión 2 presentará más sintaxis sintáctica y posiblemente menos reglas para memorizar. Hay mucha demanda para que el análisis del anidamiento no se limite o tenga momentos complicados.

La anidación es una gran mejora del lenguaje CSS. Tiene implicaciones de creación en casi todos los aspectos arquitectónicos de CSS. Este gran impacto se debe explorar y comprender en detalle antes de poder especificar la versión 2.

Para finalizar, aquí hay una demostración que usa @scope, la anidación y @layer, todo juntos. ¡Es todo 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 cyberpunk.