La capacidad de consultar el tamaño intercalado de un elemento superior y los valores de unidad de consulta del contenedor recientemente alcanzó la compatibilidad estable en todos los motores de navegador modernos.
Sin embargo, la especificación de contención incluye más que solo consultas de tamaño; también permite consultar los valores de estilo de un elemento superior. A partir de Chromium 111, podrás aplicar el aislamiento de diseño para los valores de propiedades personalizadas y consultar un elemento superior para obtener el valor de una propiedad personalizada.
Esto significa que tenemos aún más control lógico de los estilos en CSS y permite una mejor separación de la lógica y la capa de datos de una aplicación de sus estilos.
La especificación del nivel 3 del módulo de contención de CSS, que abarca las consultas de tamaño y estilo, permite consultar cualquier estilo desde un elemento superior, incluidos los pares de propiedad y valor, como font-weight: 800
. Sin embargo, en el lanzamiento de esta función, las consultas de estilo actualmente solo funcionan con valores de propiedades personalizadas de CSS. Esto sigue siendo muy útil para combinar estilos y separar los datos del diseño. Veamos cómo usar consultas de estilo con propiedades personalizadas de CSS:
Cómo comenzar a usar las consultas de estilo
Supongamos que tenemos el siguiente código HTML:
<ul class="card-list">
<li class="card-container">
<div class="card">
...
</div>
</li>
</ul>
Para usar consultas de diseño, primero debes configurar un elemento de contenedor. Esto requiere un enfoque ligeramente diferente según si consultas un elemento superior directo o indirecto.
Cómo consultar los elementos superiores directos
A diferencia de las consultas de diseño, no es necesario aplicar el aislamiento con la propiedad container-type
o container
a .card-container
para que .card
pueda consultar los diseños de su elemento superior directo. Sin embargo, debemos aplicar los estilos (valores de propiedades personalizadas en este caso) a un contenedor (.card-container
en este caso) o a cualquier elemento que contenga el elemento al que le aplicaremos estilos en el DOM. No podemos aplicar los estilos que consultamos en el elemento directo al que le aplicamos estilos con esa consulta, ya que esto podría causar bucles infinitos.
Para consultar directamente a un elemento superior, puedes escribir lo siguiente:
/* styling .card based on the value of --theme on .card-container */
@container style(--theme: warm) {
.card {
background-color: wheat;
border-color: brown;
...
}
}
Es posible que hayas notado que la consulta de diseño une la consulta con style()
. Esto permite desambiguar los valores de tamaño de los estilos. Por ejemplo, puedes escribir una consulta para el ancho del contenedor como @container (min-width: 200px) { … }
. Esto aplicaría estilos si el contenedor superior tuviera al menos 200 px de ancho. Sin embargo, min-width
también puede ser una propiedad CSS, y puedes consultar el valor CSS de min-width
con consultas de estilo. Por eso, usarías el wrapper style()
para que la diferencia sea clara: @container style(min-width: 200px) { … }
.
Aplica diseño a elementos superiores no directos
Si deseas consultar los diseños de cualquier elemento que no sea un elemento superior directo, debes asignarle un container-name
. Por ejemplo, podemos aplicar estilos a .card
según los estilos de .card-list
si le damos a .card-list
un container-name
y hacemos referencia a él en la consulta de estilo.
/* styling .card based on the value of --moreGlobalVar on .card-list */
@container cards style(--moreGlobalVar: value) {
.card {
...
}
}
Por lo general, se recomienda asignarles nombres a los contenedores para que quede claro lo que consultas y desbloquear la capacidad de acceder a esos contenedores con mayor facilidad. Un ejemplo de cuándo esto resulta útil es si quieres aplicar diseño a elementos dentro de .card
directamente. Sin un contenedor con nombre en .card-container
, no pueden consultarlo directamente.
Pero todo esto tiene mucho más sentido en la práctica. Veamos algunos ejemplos:
Consultas de diseño en acción
Las consultas de estilo son particularmente útiles cuando tienes un componente reutilizable con varias variaciones o cuando no tienes control sobre todos tus estilos, pero necesitas aplicar cambios en ciertos casos. En este ejemplo, se muestra un conjunto de tarjetas de productos que comparten el mismo componente de tarjeta. Algunas tarjetas de productos tienen detalles o notas adicionales, como "Nuevo" o "Stock bajo", que se activan con una propiedad personalizada llamada --detail
. Además, si un producto está en “Stock bajo”, tendrá un fondo de borde rojo intenso. Es probable que este tipo de información se renderice en el servidor y se pueda aplicar a las tarjetas a través de estilos intercalados de la siguiente manera:
<div class="product-list">
<div class="product-card-container" style="--detail: new">
<div class="product-card">
<div class="media">
<img .../>
<div class="comment-block"></div>
</div>
</div>
<div class="meta">
...
</div>
</div>
<div class="product-card-container" style="--detail: low-stock">
...
</div>
<div class="product-card-container">
...
</div>
...
</div>
Con estos datos estructurados, puedes pasar valores a --detail
y usar esta propiedad personalizada de CSS para aplicar los estilos:
@container style(--detail: new) {
.comment-block {
display: block;
}
.comment-block::after {
content: 'New';
border: 1px solid currentColor;
background: white;
...
}
}
@container style(--detail: low-stock) {
.comment-block {
display: block;
}
.comment-block::after {
content: 'Low Stock';
border: 1px solid currentColor;
background: white;
...
}
.media-img {
border: 2px solid brickred;
}
}
El código anterior nos permite aplicar un chip para --detail: low-stock
y --detail: new
, pero es posible que hayas notado cierta redundancia en el bloque de código. Actualmente, no hay forma de consultar solo la presencia de --detail
con @container style(--detail)
, lo que permitiría compartir mejor los estilos y reducir las repeticiones. Actualmente, esta función está en discusión en el grupo de trabajo.
Tarjetas del clima
En el ejemplo anterior, se usó una sola propiedad personalizada con varios valores posibles para aplicar estilos. Sin embargo, también puedes combinarlas usando y consultando varias propiedades personalizadas. Observa este ejemplo de tarjeta del clima:
Para aplicar diseño a los gradientes de fondo y los íconos de estas tarjetas, busca características del clima, como "nublado", "lluvioso" o "soleado":
@container style(--sunny: true) {
.weather-card {
background: linear-gradient(-30deg, yellow, orange);
}
.weather-card:after {
content: url(<data-uri-for-demo-brevity>);
background: gold;
}
}
De esta manera, puedes aplicar diseño a cada tarjeta según sus características únicas. Sin embargo, también puedes aplicar diseño a combinaciones de características (propiedades personalizadas) con el combinador and
de la misma manera que lo haces con las consultas de medios. Por ejemplo, un día nublado y soleado se vería de la siguiente manera:
@container style(--sunny: true) and style(--cloudy: true) {
.weather-card {
background: linear-gradient(24deg, pink, violet);
}
.weather-card:after {
content: url(<data-uri-for-demo-brevity>);
background: violet;
}
}
Separación de los datos del diseño
En ambas demostraciones, hay un beneficio estructural de separar la capa de datos (el DOM que se renderizaría en la página) de los estilos aplicados. Los estilos se escriben como posibles variantes que se encuentran dentro del estilo de los componentes, mientras que un extremo podría enviar los datos que luego usaría para aplicarle un estilo al componente. Puedes usar un solo valor, como en el primer caso, actualizar el valor --detail
o varias variables, como en el segundo caso (configurar --rainy
, --cloudy
o --sunny
). Y lo mejor es que también puedes combinar estos valores. Si buscas --sunny
y --cloudy
, podrías mostrar un estilo parcialmente nublado.
La actualización de los valores de propiedades personalizadas a través de JavaScript se puede realizar sin problemas, ya sea mientras se configura el modelo DOM (es decir, mientras se compila el componente en un framework) o se actualiza en cualquier momento con <parentElem>.style.setProperty('--myProperty’, <value>)
. I
Esta es una demostración que, en unas pocas líneas de código, actualiza el --theme
de un botón y aplica estilos con consultas de estilo y esa propiedad personalizada (--theme
):
Aplica diseño a la tarjeta con consultas de diseño. El código JavaScript que se usa para actualizar los valores de la propiedad personalizada es el siguiente:
const themePicker = document.querySelector('#theme-picker')
const btnParent = document.querySelector('.btn-section');
themePicker.addEventListener('input', (e) => {
btnParent.style.setProperty('--theme', e.target.value);
})
Las funciones que se detallan en este artículo son solo el comienzo. Puedes esperar más de las consultas de contenedor para ayudarte a crear interfaces dinámicas y responsivas. En cuanto a las consultas de estilo, aún hay algunos problemas abiertos. Una es la implementación de consultas de estilo para estilos de CSS más allá de las propiedades personalizadas. Esto ya forma parte del nivel de especificación actual, pero aún no se implementó en ningún navegador. Se espera que la evaluación de contexto booleano se agregue al nivel de especificación actual cuando se resuelva el problema pendiente, mientras que la consulta de rango se planifica para el siguiente nivel de la especificación.