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 la contención de estilos a los valores de las propiedades personalizadas y consultar el valor de una propiedad personalizada en un elemento superior.
Esto significa que tenemos un control aún más 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 que cualquier estilo se consulte 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 puedes utilizar las consultas de estilo con las 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 contenedor. Esto requiere un enfoque ligeramente diferente según si consultas un elemento superior directo o indirecto.
Consulta a los elementos superiores directos
A diferencia de las consultas de estilo, no necesitas aplicar contención mediante las propiedades container-type
o container
a .card-container
para que .card
pueda consultar los estilos de su elemento superior directo. Sin embargo, debemos aplicar los estilos (en este caso, los valores de propiedad personalizada) a un contenedor (en este caso, .card-container
) o a cualquier elemento que contenga el elemento al que aplicaremos diseño en el DOM. No podemos aplicar los estilos que consultamos en el elemento directo al que aplicamos diseño con esa consulta porque 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;
...
}
}
Quizás hayas notado que la consulta de estilo une la consulta con style()
. Esto es para 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 tenía 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, debes usar el wrapper style()
para que la diferencia sea clara: @container style(min-width: 200px) { … }
.
Aplica diseño a elementos superiores no directos
Si quieres consultar 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 otorgamos 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 dejar en claro lo que consultas y desbloquear la capacidad de acceder a ellos 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 múltiples variaciones o cuando no tienes control sobre todos los 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 se encuentra en stock bajo, tendrá un fondo con un borde de color rojo intenso. Es probable que este tipo de información se renderice en el servidor y se pueda aplicar a las tarjetas mediante 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 la repetición. Actualmente, esta función está en discusión en el grupo de trabajo.
Tarjetas del clima
En el ejemplo anterior, se usaba una sola propiedad personalizada con varios valores posibles para aplicar estilos. Pero también puedes mezclarlos si usas y consultan varias propiedades personalizadas. Tomemos 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 estilos para combinaciones de características (propiedad personalizada) usando el combinador and
de la misma manera que en 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 definir el estilo del componente. Puedes usar un solo valor, como en el primer caso, actualizar el valor --detail
o usar varias variables, como en el segundo caso (configurar --rainy
, --cloudy
o --sunny
). La mejor parte es que también puedes combinar estos valores, por lo que si se verifican --sunny
y --cloudy
, se podría 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 en la que, en unas pocas líneas de código, actualiza el --theme
de un botón y aplica estilos mediante 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 detalladas en este artículo son solo el comienzo. Las consultas de contenedores ofrecen más beneficios que te ayudarán 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 especificaciones actual cuando el problema pendiente se resuelva, mientras que la consulta de rango está planificada para el siguiente nivel de la especificación.