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.

Antes de la anidación, cada selector debía declararse de forma explícita, por separado. Esto genera repetición, hojas de estilo masivas 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 pueden continuar y las reglas de estilo relacionadas se pueden agrupar dentro de ellos.

Después
.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

Prueba esto en el navegador.

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

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

La anidación está disponible desde Chrome 112 y también se puede probar en Safari Technical Preview 162.

Comienza a usar la anidación de CSS

En el resto de esta entrada,se usa el siguiente entorno 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, 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 del entorno 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 contenedor .demo. A continuación, se muestra una vista previa de los elementos HTML a los que te orientarás.

<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

La anidación 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 .child selector de clase está anidado dentro de el .parent selector de clase. Esto significa que el selector .child anidado solo se aplicará a los elementos que sean elementos secundarios de elementos con una clase .parent.

Este ejemplo también 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 equivalentes en cuanto a funcionalidad, y el motivo por el que tienes opciones se aclarará a medida que se exploren ejemplos más avanzados en este artículo.

Selecciona los círculos

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

Sin anidación, CSS hoy:

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

Con anidación, existen 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 .circle clase están desenfocados y casi invisibles:

La cuadrícula colorida de formas ya no tiene círculos, sino que son muy tenues en el fondo.
Probar una demostración

Selecciona cualquier triángulo y cuadrado

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

Sin anidación, CSS hoy, existen 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 anidación, 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 los elementos .circle permanecen dentro de .demo:

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

Selecciona triángulos y círculos grandes

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

Sin anidación, CSS hoy:

.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 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 formas 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 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 esperas. El motivo es que, sin & para especificar el resultado deseado de .lg.triangle, .lg.circle combinados, 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, CSS hoy:

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

Con anidación, 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 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 anidación

La especificación de CSS para la anidación incluye 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 anidación de CSS para ayudarte a comprender la amplitud de las capacidades que introduce.

Anidación @media

Puede ser muy distractor pasar a un área diferente de la hoja de estilo para encontrar condiciones de consultas de medios que modifiquen un selector y sus estilos. Esa distracción desaparece con la capacidad de anidar las condiciones directamente 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 & 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 &, mientras que también se orienta a las tarjetas .large para demostrar que las funciones de anidación adicionales siguen funcionando.

Obtén más información sobre la anidación de @rules.

Anidación en cualquier lugar

Todos los ejemplos hasta este punto continuaron o se agregaron a un contexto anterior. Puedes cambiar o reorganizar por completo 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 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álidos

Existen algunas situaciones de sintaxis de anidación 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 de CSS cuentan con la capacidad de anidación para 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 complicado

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

Considera el siguiente bloque de CSS de anidación:

.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 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 las listas de selectores, en especial aquellas que incluyen un selector de ID.

Para que funcione el intent de la anidación, el navegador ajustará cualquier lista de selectores que no sea la anidación más interna con :is(). Este ajuste mantiene la agrupación de la lista de selectores 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 entre paréntesis. Así es como :is() siempre funciona, pero puede ser una sorpresa cuando se usa la sintaxis de anidación porque no es exactamente lo que se creó. El truco resumido; la anidación 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 anida dentro de una lista de selectores que usa un selector de ID, la especificidad de toda la anidación dentro de esa lista de selectores será alta.

Mezcla de anidación y declaraciones

Considera el siguiente bloque de CSS de anidación:

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

El color de los elementos .card será blue.

Cualquier declaración de estilo intercalada 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 la especificación.

Hay formas de evitarlo. A continuación, se ajustan los tres estilos de color en &, lo que mantiene el orden en cascada según lo previsto por el autor. El color de los elementos .card será rojo.

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

De hecho, es una práctica recomendada ajustar cualquier estilo 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 formas excelentes de detectar funciones de anidación de CSS: usar la anidación o usar @supports para verificar la capacidad de análisis del 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 el anidamiento de CSS. Debajo de esa pregunta, hay un cuadro verde que indica que se brinda asistencia.

Usa la anidación:

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

  .no-nesting {
    display: none;
  }
}

Usa @supports:

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

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

Depuración con las Herramientas para desarrolladores de Chrome

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

Captura de pantalla de la sintaxis de anidación 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

La anidación de CSS solo está en la versión 1. La versión 2 introducirá más azúcar sintáctico y, posiblemente, menos reglas para memorizar. Hay mucha demanda para que el análisis de la anidación no sea limitado ni tenga momentos complicados.

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

Como reflexión final, aquí tienes una demostración que usa @scope, anidación y @layer en conjunto. ¡Son conceptos muy emocionantes!

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.