El problema
A menudo, necesitamos combinar criterios de filtrado de diferentes tipos, p.ej., selectores + consultas de medios, consultas de medios + consultas de contenedores, etcétera.
Por ejemplo, combinar (prefers-color-scheme: dark) con un selector que se oriente a las anulaciones del esquema de colores (p.ej., :root:has(> head > meta[name="color-scheme"][content="dark"]) o :root.dark) para aplicar ciertos estilos en el modo claro o en el modo oscuro, independientemente de cómo se haya configurado el esquema de colores.
El enfoque ingenuo genera código duplicado:
/* Light mode styles */
.card.featured {
font-weight: 400;
}
#logo-dark {
display: none;
}
@media (prefers-color-scheme: dark) {
/* Dark mode styles */
:root:not(.light) {
.card.featured {
font-weight: 300;
}
#logo-dark {
display: inline;
}
#logo {
display: none;
}
}
}
/* Dark mode styles, again */
:root.dark {
.card.featured {
font-weight: 300;
}
#logo-dark {
display: inline;
}
#logo {
display: none;
}
}
Qué hacer en su lugar
Almacena el resultado del filtro combinado en una propiedad personalizada y, luego, usa consultas de estilo de contenedor para establecer reglas basadas en esa propiedad.
IMPORTANTE: Debido a cómo funcionan las consultas de contenedor, esta técnica solo funciona si podemos establecer la propiedad personalizada en un elemento superior de cualquier regla que deba coincidir.
1. Desvincula la lógica de selección de las reglas aplicadas
:root {
--color-scheme: light;
@media (prefers-color-scheme: dark) {
--color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="dark"]) {
--color-scheme: dark;
}
&:has(> head > meta[name="color-scheme"][content="light"]) {
--color-scheme: light;
}
}
2. Clave de la propiedad personalizada para las reglas aplicadas
@container not style(--color-scheme: dark) {
.card.featured {
font-weight: 400;
}
#logo-dark {
display: none;
}
}
@container style(--color-scheme: dark) {
.card.featured {
font-weight: 300;
}
#logo {
display: none;
}
}
3. OPCIONAL: Clases de utilidad para activar o desactivar la visibilidad
Un caso muy común es activar o desactivar la visibilidad según si se cumplen los criterios.
Las clases de utilidad deben prevalecer sobre los estilos de componentes arbitrarios (por lo tanto, !important) y su display que se muestra es desconocido, por lo que no pueden usar anulaciones; contrólalas con not style(...):
@container not style(--color-scheme: dark) {
.if-dark {
display: none !important;
}
}
@container not style(--color-scheme: light) {
.if-light {
display: none !important;
}
}
Protocolos de contingencia
Existen dos tipos de resguardos, según la importancia de la ramificación y lo que constituye un resguardo aceptable.
- Para la ramificación crítica, en la que todos los estados deben funcionar correctamente incluso si no se admiten las consultas de estilo, simplemente no puedes usar consultas de estilo. En su lugar, usa el enfoque ingenuo anterior y duplica las reglas para cada estado. Las clases de utilidad se pueden seguir usando, siempre y cuando también se definan de esa manera.
- Para las ramificaciones no críticas, en las que un estado predeterminado es aceptable, puedes definir los estilos base fuera de cualquier regla
@containery solo usar consultas de estilo como anulaciones. Esto preserva la mayor parte del espíritu de este enfoque, y su principal desventaja es el acoplamiento de valores que introducen las anulaciones.
#logo-dark {
display: none;
}
@container style(--color-scheme: dark) {
#logo-dark {
display: inline; /* override */
}
#logo {
display: none;
}
}