wandres.dev
CONTAINER STYLE QUERIES · Consultar custom properties

Consultar un valor, no un tamaño

La función style() dentro de @container, por qué todo elemento es contenedor de estilo sin declarar nada, y qué problema resuelve que los selectores no resolvían.

⏱ 16 min

Las container queries de tamaño preguntan cuánto espacio hay. Las de estilo preguntan otra cosa completamente distinta: qué valor tiene una custom property en un ancestro. La sintaxis comparte at-rule con las de tamaño y ahí acaban los parecidos, porque no necesitan container-type, no aplican containment, no tienen coste de layout y responden a una pregunta que hasta ahora solo se podía responder con selectores de atributo o con clases propagadas a mano.

🎯 Al terminar esta lección sabrás
  • Escribir una consulta de estilo con style() y combinarla con and, or y not.
  • Explicar por qué todo elemento es contenedor de consultas de estilo sin declarar nada.
  • Distinguir qué resuelve una consulta de estilo que un selector no resuelve.
  • Reconocer la única cosa que hoy se puede consultar y las que no.

La sintaxis

.aviso { --tono: neutro; }
.aviso.critico { --tono: peligro; }

@container style(--tono: peligro) {
  .aviso__icono { color: oklch(0.62 0.22 25); }
  .aviso__titulo { font-weight: 700; }
  .aviso__borde { border-color: currentColor; }
}

La condición se lee como “si en mi contenedor la custom property --tono vale peligro”. Las reglas de dentro se aplican, como siempre, a los descendientes del contenedor, no al contenedor mismo.

Se puede combinar como cualquier otra condición:

@container style(--tono: peligro) and style(--densidad: compacta) { /* ... */ }
@container style(--tono: aviso) or style(--tono: peligro) { /* ... */ }
@container not style(--tono: neutro) { /* ... */ }

Y se puede mezclar con una consulta de tamaño en la misma regla, porque las dos son condiciones del mismo at-rule:

@container tarjeta (inline-size > 30rem) and style(--tono: peligro) { /* ... */ }

Todo elemento es contenedor de estilo

Esta es la diferencia estructural con las consultas de tamaño y la que más desconcierta al principio. Para consultar el tamaño hace falta declarar container-type, porque hace falta el containment que garantiza la terminación. Para consultar un valor no hace falta nada: cualquier elemento es contenedor de consultas de estilo, incluido uno con container-type: normal, que es el valor por defecto de todo.

La razón es que no hay circularidad que romper. El valor de una custom property en el contenedor no depende de los estilos que la consulta aplique a los descendientes, así que no hay realimentación posible y no hace falta aislar nada.

La consecuencia práctica hay que tenerla muy presente: una consulta de estilo sin nombre se resuelve contra el elemento padre, porque el padre siempre es contenedor válido. Nunca contra un abuelo, salvo que uses container-name para pedirlo explícitamente.

.panel { --tema: oscuro; }

/* se evalua sobre el PADRE de cada elemento que coincida con el selector */
@container style(--tema: oscuro) { .boton { border-color: white; } }

/* se evalua sobre el ancestro llamado panel */
.panel { container-name: panel; }
@container panel style(--tema: oscuro) { .boton { border-color: white; } }

Como las custom properties se heredan, en la práctica --tema vale oscuro en todos los descendientes del panel, y por tanto también en el padre de cada botón, así que las dos versiones suelen coincidir. Suelen. La lección 26.4 se dedica entera a los casos en que no.

⚠️
Un contenedor sigue sin poder consultarse a sí mismo

La regla del ancestro se mantiene igual que con las consultas de tamaño: @container style(...) nunca afecta al elemento donde declaraste la propiedad. Si pones --tono: peligro en .aviso y quieres cambiar el borde de .aviso, la consulta de estilo no te sirve; necesitas un selector de atributo o de clase sobre el propio elemento. Aquí no hay riesgo de bucle, pero la especificación mantuvo la restricción por coherencia con el resto del modelo.

Qué resuelve que un selector no resolvía

La pregunta legítima es por qué no usar [data-tono="peligro"] .aviso__icono y acabar antes. En muchos casos es exactamente lo que hay que hacer, y conviene decirlo antes de vender la función. Hay dos situaciones donde la consulta de estilo aporta algo real.

La propiedad la fija otro y a otra altura. Un selector de descendiente exige que tú conozcas la clase del ancestro. Una custom property heredada llega desde donde sea, la puede poner el consumidor del componente, un tema, un contexto o incluso JavaScript, y tu componente reacciona sin saber quién ni dónde.

El valor se calcula. Una custom property puede venir de var() con fallback, de una cadena de sustituciones o de un @property con valor inicial. Un selector solo puede comprobar lo que está escrito en el marcado; una consulta de estilo comprueba el valor computado, que puede ser el resultado de toda la cascada.

/* el consumidor decide, el componente reacciona, y no hay clases acopladas */
.zona-peligrosa { --tono: peligro; }
.zona-normal    { --tono: neutro; }

Lo que hoy se puede consultar y lo que no

La especificación contempla consultar cualquier propiedad, incluidas las estándar, y también comparaciones de rango sobre propiedades numéricas registradas. En agosto de 2026, lo único implementado en algún navegador es la igualdad sobre custom properties.

@container style(--tono: peligro) { /* funciona */ }

@container style(font-style: italic) { /* NO implementado en ningun motor */ }
@container style(--nivel > 3) { /* NO implementado en ningun motor */ }

Esto no es un detalle menor: la mitad de los ejemplos que circulan por artículos antiguos usan propiedades estándar y no funcionan en ningún sitio. La lección siguiente entra en el estado de soporte con fechas y versiones concretas, porque es la información que de verdad determina si puedes usar esto en producción.

La consulta de estilo es paso de mensajes hacia abajo por el árbol

Merece la pena ver esta función por lo que es en términos de arquitectura y no de sintaxis. Una custom property heredada es un canal de comunicación descendente: un ancestro deposita un valor y cualquier descendiente, a cualquier profundidad y sin conocer la ruta, lo lee. Hasta ahora ese canal solo servía para transportar valores que se usan directamente —un color, una medida— y por tanto solo podías reaccionar a él sustituyéndolo en una propiedad. La consulta de estilo convierte ese canal en un canal de control: el valor deja de tener que ser usable como valor y pasa a poder ser una señal que dispara un bloque entero de reglas. Es exactamente la diferencia entre pasar un color y pasar un modo. En términos de sistemas de componentes es la diferencia entre una variable de contexto que se pinta y una variable de contexto sobre la que se ramifica, y el salto de expresividad es el mismo que hay entre interpolar un dato en una plantilla y tener un condicional. Cuando pienses en dónde usarla, no pienses en “qué estilos quiero cambiar”: piensa en qué decisión quiere comunicar un ancestro a descendientes que él no conoce. Si la respuesta a esa pregunta es clara, la consulta de estilo es la herramienta; si no lo es, casi siempre bastaba con un atributo.