Profundización en las consultas de estilo de contenedor | trucos CSS
Hace un tiempo escribí algunos pensamientos iniciales sobre las solicitudes de estilo de contenedor. Todavía es temprano. Ya están definidos en Especificación de nivel 1 del módulo de contención CSS (actualmente en estado de borrador del editor), pero todavía hay varias discusiones inconclusas.
La idea básica es que podemos definir un contenedor y luego aplicar condicionalmente estilos a sus descendientes en función de su estilo calculado.
@container <name>? <conditions> {
/* conditional styles */
}
El mejor ejemplo que he visto hasta ahora es quitar la cursiva de algo como esto <em>
, <i>
y <q>
cuando se usa en un contexto donde el contenido ya está en cursiva:
em, i, q {
font-style: italic; /* default UA behavior */
}
/* When the container's font-style is italic, remove italics from these elements. */
@container style(font-style: italic) {
em, i, q {
font-style: normal;
}
}
Esa es la idea general. Pero en caso de que no lo supiera, Miriam Suzanne, quien es la editora de especificaciones, mantiene un conjunto actualizado y completo de notas personales sobre solicitudes de estilo de contenedor que está disponible públicamente. Se actualizó el otro día y pasé algún tiempo tratando de cubrir los aspectos más matizados de las solicitudes de estilo. Esto es material no oficial, pero pensé en escribir algunas cosas que me llamaron la atención ¿Quién sabe? ¡Tal vez estas son cosas que finalmente podemos esperar!
Cada elemento es un contenedor de estilo.
Ni siquiera necesitamos establecer explícitamente un container-name
o container-type
para definir un contenedor de estilo porque todo es un contenedor de estilo por defecto.
Entonces, ¿ves ese ejemplo anterior que elimina las cursivas? Tenga en cuenta que no identifica un contenedor. Salta directamente a la consulta usando style()
Entonces, ¿qué contenedor se consulta? Esto será padre directo de los elementos obtener los estilos aplicados. Y si no es eso, entonces es el siguiente contenedor relativo más cercano que hay una ventaja.
Me gusta esto. Es muy CSS-y que la consulta busque una coincidencia y luego siga apareciendo hasta que encuentre una condición coincidente.
Fue difícil para mi pequeño cerebro entender por qué podíamos salirnos con la nuestra con un contenedor implícito basado en estilos, pero no tanto cuando se trata de consultas dimensionales como size
y inline-size
.Miriam lo explica bien:
Las consultas dimensionales requieren css detención sobre el tamaño, el diseño y el estilo del contenedor para evitar bucles de diseño. La restricción es algo invasivo que debe aplicarse ampliamente, por lo que era importante que los autores tuvieran un control cuidadoso sobre qué elementos son (o no son) contenedores de tamaño.
Las consultas basadas en estilos no tienen la misma limitación. Ya no hay una forma en CSS para que los estilos heredados afecten los estilos calculados de un ancestro. Por lo tanto, no se requieren restricciones y no hay efectos secundarios invasivos o inesperados al establecer un elemento como contenedor de solicitud de estilo.
(énfasis mío)
Todo se reduce a las consecuencias, de las cuales no hay ninguna, siempre que todo sea un contenedor de solicitud de estilo listo para usar.
- Si se encuentra un contenedor: las condiciones se resuelven contra ese contenedor.
- Si coinciden varios contenedores: el contenedor relativo más cercano tiene prioridad.
- Si no se encuentran coincidencias:
unknown
devuelto
Es el mismo espíritu de "perdón" que el resto de CSS.
Un contenedor puede admitir consultas de tamaño y estilo.
Digamos que queremos definir una consulta de estilo sin explícitamente container-name
:
@container style(font-style: italic) {
em {
font-style: normal;
}
}
Esto funciona porque todos los elementos son contenedores de estiloindependientemente de container-type
Esto es lo que nos permite realizar solicitudes de estilo implícitas y confiar en la coincidencia más cercana. Y eso está perfectamente bien, ya que, de nuevo, no hay efectos secundarios adversos al establecer contenedores de estilo.
Debemos usar explícitamente container-type
para consultas de tamaño, pero no tanto para consultas de estilo ya que cada elemento es una consulta de estilo. Esto también significa que este contenedor es tanto un estilo y solicitud de tamaño:
.card-container {
container: card / inline-size; /* implictly a style query container as well */
}
Excluir un contenedor de una solicitud
Tal vez no queramos que un contenedor participe en el proceso de mapeo. Aquí es donde podría ser posible establecer container-type: none
por elemento.
.some-element {
container-type: none;
}
Los contenedores de consulta con estilos explícitos ofrecen más control sobre lo que se solicita
Si, por ejemplo, tuviéramos que escribir una consulta de estilo para padding
no existe una forma confiable de determinar el contenedor más apropiado, ya sea que se trate de un contenedor con nombre explícito o del padre directo más cercano. Es así porque padding
propiedad no heredada.
Así que en estos casos tenemos que usar container-name
para informar explícitamente al navegador de qué contenedores pueden descargar. Incluso podemos dar a un contenedor varios nombres explícitos para que coincida con más condiciones:
.card {
container-name: card layout theme;
}
Oh y container-name
acepta cualquier número de opcionales y reutilizable nombres de contenedores! Esto es aún más flexibilidad cuando se trata de ayudar al navegador a tomar decisiones al buscar coincidencias.
.theme {
container-name: theme;
}
.grid {
container-name: layout;
}
.card {
container-name: card layout theme;
}
Me pregunto si esto también podría considerarse una "copia de seguridad" en caso de que se pierda un contenedor.
Las solicitudes de estilo se pueden combinar
los or
y and
nuestros operadores combinemos wueries para mantener las cosas SECAS:
@container bubble style(--arrow-position: start start) or style(--arrow-position: end start) {
.bubble::after {
border-block-end-color: inherit;
inset-block-end: 100%;
}
}
/* is the same as... */
@container bubble style(--arrow-position: start start) {
/* etc. */
}
@container bubble style(--arrow-position: end start) {
/* etc. */
}
Cambiar estilos
Hay poca superposición entre las solicitudes de estilo de contenedor y el Tab Atkins no oficial. propuesta de conmutadores CSSPor ejemplo, podemos pasar por dos font-style
valores, digamos italic
y normal
:
em, i, q {
font-style: italic;
}
@container style(font-style: italic) {
em, i, q {
font-style: normal;
}
}
Genial, pero propuesta de conmutadores CSS asume que toggle()
La función sería un enfoque más simple:
em, i, q {
font-style: toggle(italic, normal);
}
Pero cualquier cosa fuera de ese tipo de caso de uso binario es donde toggle()
es menos adecuado. Sin embargo, las solicitudes de estilo están bien. Miriam identifica tres casos donde las solicitudes de estilo son más apropiadas que toggle()
:
/* When font-style is italic, apply background color. */
/* Toggles can only handle one property at a time. */
@container style(font-style: italic) {
em, i, q {
background: lightpink;
}
}
/* When font-style is italic and --color-mode equals light */
/* Toggles can only evaluate one condition at a time */
@container style((font-style: italic) and (--color-mode: light)) {
em, i, q {
background: lightpink;
}
}
/* Apply the same query condition to multiple properties */
/* Toggles have to set each one individually as separate toggles */
@container style(font-style: italic) {
em, i, q {
/* clipped gradient text */
background: var(--feature-gradient);
background-clip: text;
box-decoration-break: clone;
color: transparent;
text-shadow: none;
}
}
Las solicitudes de estilo resuelven el "truco de cambio de propiedad personalizada"
Tenga en cuenta que las consultas de estilo son una solución oficial para el "truco de cambio de propiedad personalizada de CSS". Allí establecemos una propiedad personalizada vacía (--foo: ;
) y use el método alternativo separado por comas para "activar" y desactivar las propiedades cuando la propiedad personalizada se establece en un valor real.
button {
--is-raised: ; /* off by default */
border: 1px solid var(--is-raised, rgb(0 0 0 / 0.1));
box-shadow: var(
--is-raised,
0 1px hsl(0 0% 100% / 0.8) inset,
0 0.1em 0.1em -0.1em rgb(0 0 0 / 0.2)
);
text-shadow: var(--is-raised, 0 -1px 1px rgb(0 0 0 / 0.3));
}
button:active {
box-shadow: var(--is-raised, 0 1px 0.2em black inset);
}
#foo {
--is-raised: initial; /* turned on, all fallbacks take effect. */
}
Esto es genial, también mucho trabajo que las solicitudes de estilo de contenedor hacen trivial.
Solicitudes de estilo y contenido generado por CSS
Para contenido generado producido por content
propiedad de ::before
y ::after
Pseudoelementos, el contenedor correspondiente es el elemento sobre el que se genera el contenido.
.bubble {
--arrow-position: end end;
container: bubble;
border: medium solid green;
position: relative;
}
.bubble::after {
content: "";
border: 1em solid transparent;
position: absolute;
}
@container bubble style(--arrow-position: end end) {
.bubble::after {
border-block-start-color: inherit;
inset-block-start: 100%;
inset-inline-end: 1em;
}
}
Consultas de estilo y componentes web
Podemos definir un componente web como contenedor y consultarlo por estilo. Primero, tenemos <template>
del componente:
<template id="media-host">
<article>
<div part="img">
<slot name="img">…</slot>
</div>
<div part="content">
<slot name="title">…</slot>
<slot name="content">…</slot>
</div>
</article>
</template>
Entonces usamos :host
pseudo-elemento como un contenedor para establecer un container-name
a container-type
y algunos atributos de alto nivel en él:
:host {
container: media-host / inline-size;
--media-location: before;
--media-style: square;
--theme: light;
}
artículos dentro <media-host>
puede buscar los parámetros de <media-host>
elemento:
@container media-host style(--media-style: round) {
[part="img"] {
border-radius: 100%;
}
}
¿Qué sigue?
Una vez más, todo lo que he escrito aquí se basa en las notas de Miriam, y estas notas no reemplazan la especificación oficial. Pero son una indicación de lo que se está discutiendo y hacia dónde pueden ir las cosas en el futuro. Agradezco a Miriam que vincule un puñado de debates pendientes que aún están en curso y que podemos seguir para estar al día:
Deja una respuesta