Container Style Queries y :open: el CSS que entiende tamaño Y estado
webdevelopment 16 de septiembre de 2026 · Mintec

Container Style Queries y :open: el CSS que entiende tamaño Y estado

Desde mayo de 2026, los componentes CSS pueden adaptarse al tamaño Y al estado de su contenedor sin JavaScript. Container style queries y :open pseudo-class ya son Baseline. Análisis real con código de producción, patrones de migración y el framework de decisión que usamos en Mintec.

Container Style Queries y :open: el CSS que entiende tamaño Y estado

En mayo de 2026, dos features de CSS se convirtieron en Baseline al mismo tiempo: container style queries y el pseudo-clase :open. Juntos, cambian la forma en que construimos componentes — por primera vez, un componente CSS puede reaccionar al tamaño, al tema, y al estado de su entorno sin una sola línea de JavaScript.

Esto no es teoría. En los proyectos de Mintec — componentes de diseño, formularios, dashboards — el patrón recurrente era: el componente necesita adaptarse a su contenedor (ya resuelto con container queries de tamaño), pero también necesita responder al tema activo del padre, o a si un hijo está abierto o cerrado. La solución siempre era JavaScript: ResizeObserver para el tamaño, MutationObserver para el estado, y un montón de clases togglers que se acumulaban en cada build.

Ahora CSS resuelve las dos cosas nativamente. Veamos exactamente cómo.

El problema que resolvían los dos hacks más comunes

Hack 1: El toggle trick con custom properties

Antes de las style queries, el patrón más común para hacer componentes que respondieran al contexto era el "custom property toggle hack":

/* El padre setea un custom property */
.card {
  --theme: light;
}
.card[data-theme="dark"] {
  --theme: dark;
}

/* El hijo lo lee con --theme, pero NO puede condicionalmente estilizar basándose en su valor */
.card-header {
  background: var(--theme); /* funciona, pero es pasivo */
}

El problema: el componente hereda el valor, pero no puede reaccionar condicionalmente a él. Si --theme es "dark", el componente no tiene forma de decir "si el tema es dark, ajusta esto". La única salida era JavaScript que leyera el custom property y aplicara clases.

Hack 2: El state tracking con JavaScript

Para el estado abierto/cerrado, el patrón era:

// Cada control necesitaba su observer
const details = document.querySelector('details');
details.addEventListener('toggle', () => {
  details.classList.toggle('is-open', details.open);
  details.closest('.accordion')?.classList.toggle('has-open-child', details.open);
});

Cada <details>, cada <dialog>, cada <select> necesitaba su propio listener. Y si necesitabas estilizar un ancestro basándose en el estado de un hijo (el patrón accordion más común del mundo), necesitabas burbuear el evento hacia arriba.

Las dos soluciones nativas eliminan ambos hacks.

Container style queries: el componente que lee el contexto

Las container style queries extienden @container para que puedas consultar no solo el tamaño, sino las propiedades personalizadas de un contenedor:

/* El contenedor declara soporte de containment */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Consulta de tamaño (ya existía) */
@container card (min-width: 400px) {
  .card { display: grid; grid-template-columns: 200px 1fr; }
}

/* Consulta de estilo — ¡ESTO ES NUEVO! */
@container card style(--theme: dark) {
  .card-title { color: #f0f0f0; }
  .card-body { background: #1a1a2e; }
}

La diferencia crucial: la query de estilo no pregunta "¿cuánto mide el contenedor?" sino "¿qué valor tiene esta custom property en el contenedor?" El componente se adapta al contexto visual, no solo al espacio disponible.

Registro de propiedades para comparaciones precisas

Para que las comparaciones de valores sean exactas, registra las propiedades con @property:

@property --theme {
  syntax: "<color>";
  initial-value: #ffffff;
  inherits: true;
}

@container style(--theme: #1a1a2e) {
  .card-body { background: #0d0d1a; }
}

@property le da al navegador el tipo de la propiedad, así que style(--theme: #1a1a2e) compara colores, no strings.

El patrón de Design System con style queries

En un design system real, las style queries eliminan la necesidad de pasar props para variantes:

/* Un solo componente, múltiples contextos */
.button {
  padding: 0.75rem 1.5rem;
  border-radius: 0.5rem;
  font-weight: 600;
}

@container style(--variant: primary) {
  .button {
    background: #2563eb;
    color: white;
  }
}

@container style(--variant: danger) {
  .button {
    background: #dc2626;
    color: white;
  }
}

@container style(--size: compact) {
  .button {
    padding: 0.375rem 0.75rem;
    font-size: 0.875rem;
  }
}

El padre setea --variant y --size como custom properties, y el componente se adapta sin recibir una sola prop adicional. Esto es particularmente valioso en sistemas donde el contenido es dinámico — un CMS que renderiza componentes en diferentes contextos sin controlar las clases que recibe.

:open: un selector para todos los controles abiertos

:open es un pseudo-clase que selecciona cualquier elemento con estado abierto/cerrado mientras está en estado abierto. Cubre más elementos de los que esperas:

/* Details expandido */
details:open > summary {
  background: #eef2ff;
  border-bottom: 1px solid #c7d2fe;
}

/* Dialog mostrado */
dialog:open {
  opacity: 1;
  transform: scale(1);
}

/* ¡Select con dropdown visible! — esto era imposible antes */
select:open {
  border-color: #4f46e5;
  box-shadow: 0 0 0 3px rgb(79 70 229 / 0.2);
}

/* Input picker (color, date, etc.) abierto */
input[type="color"]:open {
  outline: 2px solid #4f46e5;
}

Lo que hace :open especial: antes de mayo de 2026, el estado de un <select> dropdown era invisible para CSS. No existía ningún selector que dijera "este select tiene el picker abierto". Los desarrolladores usaban focus-within como proxy — que no es lo mismo, porque un select puede tener foco sin tener el picker abierto, y viceversa.

:open + :has(): el patrón accordion definitivo

El uso más inmediato de :open es combinarlo con :has() para estilizar ancestros basándose en el estado de sus hijos:

/* El accordion card cambia cuando uno de sus detalles está abierto */
.accordion-card:has(details:open) {
  box-shadow: 0 12px 32px rgb(15 15 14 / 0.08);
  border-color: var(--ink-25);
}

/* El field se eleva cuando su select tiene el picker abierto */
.form-field:has(select:open) {
  z-index: 10;
  position: relative;
}

/* El grupo de radios muestra indicador visual activo */
.radio-group:has(input:checked:open) {
  border-color: var(--accent);
}

Antes de :open, necesitabas JavaScript para cada accordion, cada form field, cada custom dropdown. Ahora CSS lo resuelve nativamente — y el selector lee como el comportamiento que representa.

La intersección: style queries + :open + :has()

Aquí es donde se pone interesante. Los tres features se combinan para crear componentes que responden al tamaño, al tema, y al estado:

/* El form field reacciona a: tamaño del contenedor, tema activo, Y si su select está abierto */
@container form-field style(--theme: dark) {
  .field-label { color: #e2e8f0; }
  .field-input { border-color: #4a5568; }
}

/* Cuando el select del field está abierto, el field se adapta */
.form-field:has(select:open) {
  z-index: 10;
}

@container form-field style(--theme: dark) {
  .form-field:has(select:open) {
    box-shadow: 0 0 0 3px rgb(99 102 241 / 0.3);
  }
}

Un componente, cero JavaScript, tres dimensiones de adaptación.

Rendimiento: containment como requisito

Las container style queries — al igual que las de tamaño — requieren contain: layout inline-size style en el contenedor. Esto le dice al navegador que puede optimizar la recalculación de estilos porque los cambios dentro del contenedor no afectan afuera.

En la práctica, esto es una ventaja de rendimiento, no un costo: el navegador puede limitar el recálculo de estilos al alcance del contenedor en lugar de recorrer todo el DOM. En dashboards con muchos componentes repetidos, la diferencia es medible.

Regla práctica en Mintec: container-type: inline-size para consultas de tamaño, container-type: normal para consultas de estilo (cuando no necesitas containment de tamaño), o ambos cuando el componente se adapta en las dos dimensiones.

Soporte de navegadores

FeatureChromeFirefoxSafariBaseline
Container style queries111+110+18+Mayo 2026
:open pseudo-class133+132+18.4+Mayo 2026
:has() selector105+121+15.4+Dic 2023

Para producción en septiembre 2026: los tres features están soportados en las versiones actuales de todos los navegadores principales. Para usuarios con navegadores anteriores, los componentes siguen funcionando — simplemente pierden la adaptación contextual y de estado.

Framework de decisión: ¿cuándo usar cada patrón?

¿El componente necesita adaptarse al tamaño de su contenedor?
├── Sí → container-type: inline-size + @container (min-width)
└── No

¿El componente necesita reaccionar al tema/variante de su padre?
├── Sí → container-type: normal + @container style(--prop: value)
└── No

¿El componente tiene estado abierto/cerrado (details, dialog, select)?
├── Sí → :open pseudo-class (sin JavaScript)
└── No

¿Necesitas estilizar un ANCESTRO basándose en el estado de un hijo?
├── Sí → :has() + :open (el selector definitivo)
└── No → usa el selector directo

La conexión con lo que ya cubrimos

Este artículo es la segunda parte de una serie sobre las container queries en producción. La primera cubrió container queries de tamaño y @scope — las preguntas que el componente hacía sobre su espacio. Este cubre las preguntas que el componente ahora hace sobre su contexto visual y su estado.

La tendencia subyacente es la misma que documentamos en nuestro análisis de la Baseline 2026 y en el adiós a ARIA con HTML nativo — CSS y HTML están absorbiendo trabajo que antes era 100% JavaScript. Cada una de estas features es incremental. El efecto acumulativo es que los problemas que requerían librerías en 2023 ahora se resuelven con el plataforma.

En Mintec, la recomendación para proyectos nuevos es clara: diseñar componentes desde el inicio con containment, custom properties registradas, y selectores de estado nativos. Los proyectos existentes pueden migrar incrementalmente — :open funciona junto a [open], y las style queries son un complemento, no un reemplazo de las size queries.


Publicado por Mintec — arquitectura web y desarrollo frontend

Preguntas Frecuentes

¿Qué son las container style queries en CSS?

Las container style queries son una extensión de las container queries que permiten estilizar componentes basándose en las propiedades personalizadas (custom properties) de su contenedor padre, no solo en su tamaño. Esto permite crear componentes que reaccionan al contexto visual — como el tema activo o el modo de color — sin JavaScript.

¿Qué es el pseudo-clase :open en CSS?

:open es un pseudo-clase que selecciona cualquier elemento con estado abierto/cerrado — <details>, <dialog>, <select>, y inputs de tipo picker — mientras está en estado abierto. Es universal: un selector para todos los controles nativos que tienen estados de apertura, disponible en todos los navegadores principales desde mayo de 2026.

¿Cómo se combinan container style queries con :open?

Se pueden anidar: un @container style query que verifica la propiedad '--expanded' de un contenedor padre, combinado con :open en un hijo, permite estilos que reaccionan tanto al contexto del contenedor como al estado del hijo. Junto con :has(), puedes estilizar un ancestro basándose en si uno de sus descendientes está abierto.

Artículos Relacionados

contrast-color() y reading-flow: el CSS de 2026 que automatiza las correcciones de accesibilidad que hacíamos a mano
webdevelopmentAug 1, 2026

contrast-color() y reading-flow: el CSS de 2026 que automatiza las correcciones de accesibilidad que hacíamos a mano

En las auditorías de accesibilidad que realizamos en Mintec, dos correcciones se repiten en casi todos los proyectos: los pares de color hardcodeados para cumplir WCAG AA y el reordenamiento manual del orden de lectura en layouts flex y grid. Ambas tienen ahora solución nativa en CSS: contrast-color() y reading-flow. Análisis con soporte real de navegadores, casos de primera mano y framework de migración.

Read Article →Mintec.Blog
Container Queries y @scope: El nuevo CSS que cambió cómo construimos componentes en 2026
webdevelopmentJun 17, 2026

Container Queries y @scope: El nuevo CSS que cambió cómo construimos componentes en 2026

Container queries y @scope CSS alcanzaron más del 93% de soporte en navegadores. Te contamos cómo migramos el sistema de diseño de un cliente de media queries a container queries, las métricas reales de rendimiento y un framework de decisión para saber cuándo usar cada técnica.

Read Article →Mintec.Blog
CSS shape(): recortes responsivos sin coordenadas fijas (adiós a path() y a las máscaras SVG frágiles)
webdevelopmentAug 6, 2026

CSS shape(): recortes responsivos sin coordenadas fijas (adiós a path() y a las máscaras SVG frágiles)

shape() es la nueva función CSS de clip-path que acepta curvas complejas con unidades CSS: porcentajes, rem, calc() e incluso unidades mixtas que mantienen el grosor de una curva mientras la forma escala. Es Baseline desde febrero de 2026 (Chrome 135+, Safari 18.4+, Firefox). Esto es lo que cambia para recortes orgánicos en imágenes y video, con el framework de decisión que usamos en los proyectos de Mintec.

Read Article →Mintec.Blog