Antecedentes y descripción general
A menudo, un autor necesitará realizar cambios contextuales en el diseño de un componente. Históricamente, los autores necesitaban usar selectores para aplicar esos cambios. Esto solía significar que, si bien muchos de sus tokens de diseño podían existir como propiedades personalizadas, los tokens de diseño de orden superior solo podían codificarse como un patrón de selector (es decir, usando una convención de nombre de clase o atributo) o como props/contexto en un framework de JavaScript.
Las consultas de estilo de contenedor permiten que los autores apliquen diseño a los elementos según el valor de la propiedad personalizada calculada de un elemento principal. Esto significa que los autores pueden escribir valores de tokens de diseño significativos en sus hojas de estilo, en lugar de depender del lenguaje de marcado o de JavaScript para la presentación.
Cómo implementarlo
Implementar un token de diseño reactivo con una consulta de estilo de contenedor es bastante sencillo:
- Establece el token de diseño de orden superior como una propiedad personalizada en un contenedor. No es necesario que sea una propiedad personalizada registrada.
- Usa la regla
@container style()para consultar el valor de esa propiedad personalizada. - Aplica los estilos adecuados a un elemento descendiente dentro del contenedor.
Debes tener en cuenta lo siguiente:
- No es necesario que el contenedor que se consulta con una consulta de estilo tenga un
container-typeocontainer-nameestablecido. Sin embargo, uncontainer-namepuede permitir una consulta más específica. - La consulta de estilo de contenedor no puede aplicar diseño al contenedor en sí.
A continuación, se muestra un ejemplo básico de los pasos de implementación anteriores.
<div class="features">
<div class="card"></div>
<div class="card"></div>
</div>
<div class="bugs">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
.features {
--density: spacious;
}
.bugs {
--density: compact;
}
@container style(--density: compact) {
.card {
padding: 8px;
}
}
@container style(--density: spacious) {
.card {
padding: 24px;
}
}
Estrategias de resguardo
Hasta que haya compatibilidad con Baseline para las consultas de estilo de contenedor, NO SE RECOMIENDA que se usen para las funciones principales que deben estar disponibles en todos los navegadores, ya que no es sencillo crear un resguardo para ellas que no les quite sus beneficios o que tenga sus propias limitaciones. Por ejemplo, si una preferencia del usuario de densidad de la IU no se considera una función principal que debe estar disponible en todas las experiencias, se pueden usar consultas de estilo de contenedor para implementar la función sin un resguardo.
Usa selectores en su lugar
Para las funciones principales, se debe usar un enfoque alternativo con selectores. En este ejemplo, se usa un atributo data-density para codificar el token de diseño de densidad en el lenguaje de marcado en lugar de como una propiedad personalizada:
<div class="features" data-density="spacious">
<div class="card"></div>
<div class="card"></div>
</div>
<div class="bugs" data-density="compact">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
/* This example uses `:where()` to avoid increasing specificity */
:where([data-density="compact"]) .card {
padding: var(--card-padding-compact);
}
:where([data-density="spacious"]) .card {
padding: var(--card-padding-spacious);
}
Una limitación importante de este enfoque de resguardo es que no admite elementos de anidamiento con el atributo data-density establecido, ya que la especificidad del selector es la misma, se usará el orden de aparición para determinar los estilos (es decir, [data-density="spacious"] siempre tendrá prioridad sobre [data-density="compact"]).
Usa consultas de estilo como una mejora progresiva
Si bien NO SE RECOMIENDA, si quieres usar consultas de estilo como una mejora progresiva para una función principal, puedes crear algunas propiedades personalizadas para evitar la duplicación y, luego, incluir las consultas de estilo. Asegúrate de que el enfoque de resguardo use :where() cuando selecciones los elementos del contenedor para evitar aumentar la especificidad.
.card {
--card-padding-compact: 8px;
--card-padding-spacious: 24px;
}
:where([data-density="compact"]) .card {
padding: var(--card-padding-compact);
}
:where([data-density="spacious"]) .card {
padding: var(--card-padding-spacious);
}
/* Use style queries as a progressive enhancement: same specificity, so order of appearance is used */
@container style(--density: compact) {
.card {
padding: var(--card-padding-compact);
}
}
@container style(--density: spacious) {
.card {
padding: var(--card-padding-spacious);
}
}
Verificación de funciones solo con CSS
Si necesitas verificar las consultas de estilo de contenedor para mostrar de forma condicional alguna IU que dependa de ellas, puedes usar una consulta de estilo para hacerlo:
:root {
--style-queries-supported: check;
}
.density-toggle {
display: none;
}
@container style(--style-queries-supported) {
.density-toggle {
display: revert;
}
}
Verificación de funciones con JavaScript
Para la verificación de funciones con JavaScript, es un poco más complicado, ya que la interfaz CSSContainerRule existía antes de que se agregaran las consultas de estilo de contenedor, por lo que no es confiable para este propósito. En su lugar, deberás verificar el valor calculado de una propiedad conocida que se establece con una consulta de estilo.
En este ejemplo, se usa una propiedad personalizada, ya que no tendrá ningún efecto visual:
:root {
--style-queries-supported: check;
}
@container style(--style-queries-supported: check) {
body {
--style-queries-supported: yes;
}
}
Luego, verifica el valor calculado en JavaScript de la siguiente manera:
if (getComputedStyle(document.body).getPropertyValue("--style-queries-supported") === "yes") {
// Use container style queries
} else {
// Use fallback strategy
}