Ya conoces el error. La cuadrícula de tarjetas “responsiva” se ve perfecta en tu portátil, se colapsa en una barra lateral
y se convierte en una pieza trágica de arte moderno dentro de un modal. Alguien añade un panel nuevo y, de repente,
tu “punto de quiebre de escritorio” se activa en un contenedor con ancho similar al móvil porque el componente se incrustó en un sitio extraño.
Las Container Queries solucionan la categoría de fallos en la que el viewport no es la señal correcta. En sistemas de producción,
la señal adecuada suele ser: “¿Cuánto espacio tiene esto realmente en este momento?” Esa es la promesa.
La realidad es: aún tienes que diseñarlo y operarlo con responsabilidad.
Por qué existen las Container Queries (y cuándo no aplican)
Las media queries se refieren al viewport. Eso está bien cuando tu layout es mayormente a nivel de página:
cabecera, contenido principal, barra lateral, pie. Es frágil cuando tu interfaz es un set de Lego:
tarjetas dentro de pestañas dentro de un cajón dentro de una cuadrícula dentro de una página.
Las Container Queries permiten que un componente se adapte según el tamaño de su contenedor, no de la ventana.
Eso significa que un “ProductCard” puede renderizarse como una fila compacta en una barra lateral estrecha y como
un diseño amplio de dos columnas en un área de contenido ancha—sin que el componente necesite saber dónde vive.
Usa container queries cuando:
- Construyes componentes reutilizables usados en múltiples layouts (dashboards, bloques CMS, sistemas de diseño).
- Tu layout incluye paneles redimensionables, vistas divididas, barras laterales, cajones y cuadrículas anidadas.
- Quieres que tus puntos de quiebre describan estados del componente, no clases de dispositivo.
No uses container queries cuando:
- Estás tomando decisiones verdaderamente a nivel de viewport (cambios en la navegación global, escalado tipográfico de página completa).
- Tu componente nunca se incrusta y el viewport es lo único que importa.
- Puedes resolverlo con layouts flexibles (grid/flex) sin necesidad de breakpoints.
Opinión: usa media queries para el encuadre de página y container queries para el interior de los componentes.
Si inviertes eso, construirás un sistema “responsivo” de una forma que nadie pidió.
Datos interesantes y breve historia
Algo de contexto ayuda porque las container queries parecen una característica CSS pequeña, pero en realidad
son un cambio en cómo modelamos la UI responsiva. Aquí hay hechos concretos que vale la pena recordar:
- Se pidieron container queries por más de una década porque los autores querían componentes modulares sin acoplamiento a breakpoints globales.
- La parte difícil no fue la sintaxis; fue evitar ciclos de layout (los estilos dependen del tamaño; el tamaño depende de estilos).
- Polifills tempranos de “element query” existieron, a menudo usando resize observers y mucho JS, y eran frágiles bajo carga real.
- Las container queries modernas llegaron primero a navegadores basados en Chromium, y luego a otros motores principales, tras mucho trabajo en la especificación sobre contención.
- La especificación vincula las queries a “contenedores de consulta”, que deben establecerse explícitamente mediante
container-type(o el atajocontainer). - Las unidades de consulta de contenedor (cqw, cqh, etc.) son relativas al contenedor de consulta, no al viewport, lo que hace que la tipografía del componente escale localmente.
- La contención existía antes que las container queries como una característica de rendimiento; las container queries convirtieron la contención en una herramienta de uso diario.
- Los sistemas de diseño impulsaron la adopción porque una única “card” puede aparecer en una lista, cuadrícula, carrusel o barra lateral—cada uno con anchos distintos.
Una cita para mantenerte honesto, desde una mentalidad de fiabilidad. Brian Kernighan dijo: “Debugging is twice as hard as writing the code.”
Si no estás seguro de la exactitud, trátalo como una idea parafraseada y compórtate en consecuencia: haz que tu lógica de container queries sea depurable.
Modelo mental: contención, contenedores de consulta y ámbito
Las container queries no son “media queries pero más pequeñas.” Introducen una nueva dependencia:
los estilos de un elemento pueden depender del tamaño de un ancestro. Suena simple hasta que recuerdas
que el tamaño puede depender de los estilos. A los motores CSS no les gustan las paradojas.
Concepto clave 1: debe existir un “contenedor de consulta”
Una container query solo funciona si hay un ancestro con container-type establecido.
Sin ello, tus reglas @container nunca coincidirán, y perderás medio día culpando al archivo equivocado.
Concepto clave 2: la contención previene ciclos
Cuando pones container-type: inline-size, le estás diciendo al navegador:
“Puedes usar mi tamaño inline (típicamente ancho) para consultas, y acepto las implicaciones de contención.”
El navegador puede entonces calcular tamaños en un orden que no genere bucles.
Si consultas ancho y alto sin cuidado, o dejas que el layout dependa del tamaño del contenido en forma circular,
puedes crear layouts inestables. La mayoría de las veces evitas lo peor consultando solo el inline size.
Es la jugada 80/20.
Concepto clave 3: el ámbito es local; los nombres ayudan
Los contenedores pueden tener nombre, y deberías nombrarlos cuando tu página tiene múltiples ancestros posibles.
De lo contrario, seleccionarás accidentalmente el contenedor más cercano y te preguntarás por qué tu componente cambia de diseño
cuando alguien lo envuelve en un div nuevo.
Broma #1: Las container queries son como organigramas: todo tiene sentido hasta que alguien añade una capa más de “envoltura” y nadie sabe quién reporta a quién.
Sintaxis esencial que realmente usarás
Definir un contenedor de consulta
Usa el atajo cuando puedas; documenta la intención.
El patrón más común es hacer que el wrapper del componente sea el contenedor de consulta.
cr0x@server:~$ cat container-queries.css
/* Query container */
.widget {
container-type: inline-size;
container-name: widget;
}
/* Query by container width */
@container widget (min-width: 480px) {
.widget .title { font-size: 1.25rem; }
.widget .meta { display: block; }
}
@container widget (max-width: 479px) {
.widget .meta { display: none; }
}
Lo importante: container-type: inline-size es la herramienta por defecto.
No empieces con size a menos que tengas una razón sólida para consultar también la altura.
Contenedores nombrados vs no nombrados
Los contenedores sin nombre funcionan, pero son una trampa en una biblioteca de componentes donde los wrappers aparecen y desaparecen.
Usa nombres para cordura entre equipos.
Unidades de consulta de contenedor (la familia “cqw”)
Las unidades de consulta de contenedor son relativas al tamaño del contenedor:
1cqw es 1% del ancho del contenedor de consulta,
1cqh es 1% de su altura, y así sucesivamente.
Permiten escalar tipografía y espaciado dentro del espacio real disponible del componente.
Consejo práctico: usa unidades de contenedor para escalados sutiles (como padding, gap, tipografía menor).
No construyas un sistema completo de tipografía fluida dentro de cada componente. Por ahí solo llega el caos.
Patrones centrados en componentes que resisten apps reales
Patrón 1: “La tarjeta cambia de apilado a dos columnas”
Este es el triunfo canónico de las container queries: una tarjeta cambia de diseño según el ancho de su contenedor,
no del viewport. Funciona en cuadrículas, barras laterales, modales y paneles divididos.
cr0x@server:~$ cat card.css
.card {
container-type: inline-size;
container-name: card;
display: grid;
gap: 12px;
}
.card__media { aspect-ratio: 16 / 9; background: #ddd; }
.card__body { display: grid; gap: 8px; }
@container card (min-width: 520px) {
.card {
grid-template-columns: 220px 1fr;
align-items: start;
}
.card__media { aspect-ratio: 1 / 1; }
}
Este patrón reduce tu dependencia de breakpoints de página. La tarjeta elige su diseño
según el espacio. La página elige columnas. Cada uno se mantiene en su responsabilidad.
Patrón 2: “La tabla se convierte en un listado de definiciones en contenedores estrechos”
Las tablas no “responden” bien. En contenedores estrechos, cambiar de representación suele ser mejor que
apretar columnas hasta que sean ilegibles. Las container queries permiten que esa decisión sea local.
En la práctica, mantienes HTML semántico tanto como sea posible. Aún puedes hacer cambios de presentación con CSS:
ocultar encabezados, mostrar filas como bloques, añadir etiquetas vía data-label.
Lo importante es evitar heurísticas basadas en el viewport. La tabla de la barra lateral no debe pretender estar en escritorio.
Patrón 3: “La barra de herramientas colapsa acciones en un menú de desbordamiento”
Si alguna vez lanzaste una barra de herramientas que colapsa en el momento equivocado, sabes por qué importan las container queries.
La barra debe reaccionar a su propio ancho, no a lo que haga la ventana en general.
Para el comportamiento real de desbordamiento, probablemente usarás JS (medir hijos y moverlos).
Las container queries aún te dan umbrales estables para cuándo cambiar de “mostrar etiquetas”
a “solo iconos” a “menú de desbordamiento”.
Patrón 4: “Componente se adapta dentro de un panel dividido redimensionable”
Los paneles redimensionables son donde los breakpoints de viewport van a morir.
Con container queries, el componente responde continuamente mientras el usuario arrastra.
Eso es UX real, no una casilla de verificación de responsividad.
Patrón 5: “Contenedores anidados: estados de componente en capas y limpios”
Anidar contenedores es válido, pero también es la forma en que obtienes comportamientos sorpresa cuando un wrapper nuevo se convierte en el contenedor más cercano.
Usa nombres de contenedor y consulta el correcto. Si el layout de tu componente depende de un wrapper específico, nómbralo y apúntalo.
Sistemas de diseño: cómo evitar el “sopa de breakpoints”
Las container queries son gasolina. Puedes impulsar un coche de carreras o puedes quemar el garaje.
En sistemas de diseño esto importa: docenas de componentes, cientos de composiciones, múltiples equipos,
y una cadencia de releases que no se detiene porque el CSS esté “casi correcto”.
Elige “clases de tamaño” de componente que puedas explicar con palabras
En un sistema de diseño, no definas breakpoints como valores de píxeles aleatorios por componente.
Define un conjunto reducido de umbrales semánticos por componente: compacto, regular, espacioso.
Mapea esos estados a anchos de contenedor. Documenta los comportamientos por estado.
Si no puedes describir un breakpoint sin mencionar un dispositivo, probablemente estás pensando en viewport.
Las container queries son pensamiento centrado en el componente. Mantente coherente.
Haz explícito el contenedor en el contrato del componente
Decide qué elemento es el contenedor de consulta. Ponlo en la API del componente y cúmplelo.
Si tu componente puede usarse de forma independiente, debería crear su propio contenedor.
Si debe heredar un contenedor, documenta el requisito—and espéralo violado a las 2 a.m.
Prefiere menos queries y primitivas de layout más sólidas
Usa grid/flex y tamaños intrínsecos primero. Luego aplica container queries para los pocos cambios de forma significativos.
Si cada 40px algo cambia, has creado una prueba de integración continua para la paciencia humana.
Estrategia de pruebas: snapshots de layouts a anchos de componente, no de viewport
Tus tests deberían renderizar el componente a anchos de contenedor representativos:
320, 420, 520, 720, etc. Esos números son ejemplos; elige los que coincidan con tus composiciones reales.
El punto es: el comportamiento del componente debe ser testeable sin un harness de página completo.
Depuración en producción: qué falla y por qué
Los modos de fallo de las container queries son mayormente operativos: la característica es simple,
pero tu DOM no lo es. Los contenedores son envueltos. Los estilos se refactorizan. Un nuevo componente de layout añade
contain o cambia el display. De repente tu componente queda “atascado” en modo compacto.
Causa raíz más común: no existe contenedor de consulta
Si container-type no está establecido (o está en el ancestro equivocado), nada coincide.
El CSS se parsea bien. No hay error en consola. Simplemente… no funciona.
Por eso necesitas una rutina de diagnóstico, no intuiciones.
Segunda causa raíz común: consultar el contenedor equivocado
Los contenedores sin nombre seleccionan el ancestro más cercano. Si un wrapper de layout se convirtió en contenedor por otra razón,
tu componente podría empezar a basarse en ese wrapper en lugar del previsto.
Los nombres previenen esto. Úsalos.
Tercera causa raíz común: acoplamiento de estilos causa jank de layout
Las container queries pueden causar “flip-flop” si una query cambia el layout lo suficiente como para alterar el tamaño del contenedor,
lo que cambia el resultado de la query, lo que vuelve a cambiar el layout. Los navegadores intentan evitar ciclos, pero aún puedes
crear transiciones con saltos o reflows inesperados.
Broma #2: Si tu componente oscila entre dos layouts, felicidades—has inventado un metrónomo CSS. Los usuarios no pidieron sincronización de jazz.
Chequeo de realidad sobre rendimiento
Las container queries están implementadas en los motores, así que evitas la pesadilla de polifills en JS.
Pero “nativo” no significa “gratis”. Si estableces contenedores en todas partes y adjuntas muchas
queries muy finas, puedes crear costes medibles de recálculo de estilos durante cambios de tamaño y dinámicos.
La solución es aburrida: menos contenedores, menos queries, mejor composición y perfilado con interacciones reales.
Es la misma disciplina que aplicas en sistemas backend: medir, acotar y simplificar.
Guía de diagnóstico rápido
Cuando un componente basado en container queries se comporta mal, quieres encontrar el cuello de botella rápido.
Aquí tienes un orden de triage amigable para producción que evita madrigueras.
1) Comprueba si existe un contenedor de consulta y cuál se usa
- Inspecciona el elemento en DevTools.
- Localiza el ancestro más cercano con
container-type(o el atajocontainer). - Si hay múltiples, confirma si pretendías el más cercano—or usa
container-namepara apuntar al correcto.
2) Comprueba el inline size real del contenedor en tiempo de ejecución
- Aún en DevTools, verifica el ancho de layout calculado del contenedor.
- Compáralo con los umbrales de las queries.
- Si está cerca de un umbral y parpadea, probablemente tienes un bucle de retroalimentación o un problema de redondeo.
3) Confirma que la condición de la query coincide con lo que piensas
- Verifica si estás usando
min-width/max-widthdentro de@containercorrectamente. - Asegúrate de que tus container queries apunten al contenedor nombrado si usaste nombres.
- Revisa si accidentalmente usaste unidades de contenedor (
cqw) esperando unidades de viewport (vw).
4) Busca ciclos de layout y efectos secundarios de la contención
- Si la query cambia padding/borders/scrollbars, puede alterar el tamaño del contenedor.
- Si consultas la altura, ten especial cuidado: el contenido cambia la altura; la altura activa la query; la query cambia el contenido.
- Prefiere contenedores con
inline-sizea menos que realmente necesites consultas de altura.
5) Perfilado antes de “optimizar”
- Si la app se entrecorta al redimensionar o abrir paneles, perfila el recálculo de estilos y el layout.
- Elimina contenedores innecesarios y reduce los umbrales de las queries.
Errores comunes: síntoma → causa raíz → solución
1) Síntoma: las reglas @container nunca se aplican
Causa raíz: Ningún ancestro tiene container-type establecido, así que no existe contenedor de consulta.
Solución: Añade container-type: inline-size al wrapper del componente (o a un wrapper de layout específico) y revisa los estilos calculados.
2) Síntoma: el componente se ve correcto en una página pero mal en un modal/barra lateral
Causa raíz: Usaste media queries para un componente que se incrusta en anchos de contenedor diferentes.
Solución: Mueve la lógica de breakpoints a container queries en el componente. Mantén las media queries solo para el encuadre de página.
3) Síntoma: el componente cambia de layout inesperadamente después de un refactor
Causa raíz: Un wrapper nuevo se convirtió en el contenedor más cercano (selección de contenedor sin nombre), cambiando cuál se consulta.
Solución: Nombra el contenedor previsto (container-name) y apúntalo explícitamente en @container.
4) Síntoma: el layout oscila cerca de un breakpoint
Causa raíz: La query cambia algo que altera el ancho del contenedor (scrollbar, padding, columnas de grid), provocando thrash de umbrales.
Solución: Añade histéresis (usa umbrales min/max ligeramente separados), evita cambios que afecten el ancho en el breakpoint, o reestructura para que el ancho del contenedor sea estable.
5) Síntoma: la tipografía escala de forma extraña en componentes anidados
Causa raíz: Las unidades de consulta de contenedor son relativas al contenedor de consulta más cercano; la anidación cambia la referencia inesperadamente.
Solución: Usa contenedores nombrados para contextos de escalado tipográfico, o prefiere tipografía en rem con pasos discretos de container query.
6) Síntoma: jank de rendimiento al redimensionar paneles o abrir cajones
Causa raíz: Demasiados contenedores y demasiados umbrales de query provocan recálculos frecuentes de estilo/layout en redimensiones dinámicos.
Solución: Reduce el alcance de los contenedores, colapsa umbrales y evita container queries para micro-cambios. Mide con herramientas de perfil antes/después.
7) Síntoma: la query funciona en un navegador pero no en otro
Causa raíz: Diferencias de soporte parcial, webviews embebidos antiguos, o herramientas de build que eliminan/reescriben at-rules desconocidos.
Solución: Añade mejora progresiva: layout base sin container queries, luego capas de mejora. Verifica que la canalización CSS preserve @container.
Tres mini-historias corporativas desde el terreno
Mini-historia 1: El incidente causado por una suposición equivocada
Un equipo lanzó una nueva “InsightCard” usada en todo un producto de analítica: dashboards, paneles laterales y un reporte de página completa.
La implementación original usaba media queries. Se veía bien en el reporte de página completa, porque, por supuesto, así era.
Luego un cliente empresarial construyó un layout personalizado: una cuadrícula de tres columnas con una barra lateral derecha plegable.
Cuando la barra se expandió, las tarjetas dentro seguían renderizando en “modo escritorio” porque el breakpoint de viewport se satisfacía.
Dentro de una barra de 320px de ancho, la tarjeta intentó mostrar una grid interna de dos columnas, etiquetas largas y una leyenda de gráfico.
El resultado fue overflow, texto recortado y una trampa de scroll dentro de un contenedor desplazable. Soporte lo llamó “inutilizable.” No estaban equivocados.
La suposición equivocada fue simple: el ancho del viewport aproxima el ancho del componente. No es así en UIs modernas.
El producto tenía paneles divididos, barras laterales fijas y módulos embebidos. El viewport era una mentira, y la mentira creció a medida que la UI maduró.
La solución no fue heroica. Definieron el wrapper de la card como un contenedor de consulta nombrado y movieron los breakpoints internos de la card a @container.
Las media queries se conservaron solo para cambios de grid a nivel de página. Una vez desplegado, la misma card se comportó correctamente en la barra, en modales y en el reporte de página completa.
Mini-historia 2: La optimización que salió mal
Otra organización se entusiasmó y trató de “estandarizar la responsividad” convirtiendo cada wrapper de layout en un contenedor de consulta.
Headers, secciones, celdas de grid, paneles—todo tenía container-type: inline-size.
Se vendió como preparación para el futuro. También fue una excelente forma de hacer la depuración imposible.
El primer problema visible fue extraño: los componentes comenzaron a responder a contenedores distintos dependiendo de dónde se renderizaban.
Un componente que esperaba consultar su propio wrapper ahora consultaba un wrapper exterior porque el DOM cambió.
El segundo problema fue menos visible pero más costoso: el coste de recálculo de estilos aumentó durante interacciones de arrastre/redimensionado.
La UI no “crasheó”, simplemente se sintió pegajosa, como arrastrar a través del barro.
La “optimización” del equipo creó un grafo de dependencias implícito gigante. Demasiados contenedores implican demasiados contextos de consulta potenciales.
Y como muchos contenedores eran redundantes, el navegador hacía trabajo extra para mantenerlos. Nada en los dashboards de rendimiento saltó alarmas.
Los usuarios simplemente dejaron de confiar en la UI.
La estrategia de rollback fue instructiva: eliminaron container-type de wrappers genéricos y lo mantuvieron solo en raíces de componentes que realmente lo necesitaban.
Nombraron contenedores clave. La depuración volvió a ser sensata, el rendimiento mejoró y el sistema volvió a ser explicable—que es lo que quieres en producción.
Mini-historia 3: La práctica aburrida pero correcta que salvó el día
Un equipo de plataforma mantenía una biblioteca de componentes usada por múltiples squads de producto.
Introdujeron las container queries con cuidado: cada componente tenía un layout base sin container queries,
luego las container queries se aplicaban como mejora progresiva. También escribieron una pequeña guía interna:
“Los breakpoints de componente deben documentarse como estados del componente, y los contenedores deben nombrarse.”
Meses después, un squad incrustó la biblioteca dentro de un entorno host de terceros con un webview antiguo.
Las container queries no se aplicaron. El squad esperaba un desastre, porque las características CSS modernas suelen fallar ruidosamente en contextos legacy.
En cambio, la UI se mantuvo usable: el layout base era simple, flexible y no dependía del soporte de queries.
La respuesta al incidente fue aburrida en el mejor sentido. Detectaron el soporte faltante en QA,
aceptaron la experiencia base para ese host y evitaron desplegar un polifill frágil.
El producto siguió funcionando. El release se mantuvo en calendario. Nadie se quedó a toda la noche peleando con CSS.
Este es el tipo de “éxito de ingeniería” que nunca se convierte en leyenda porque no crea drama.
Simplemente lo previene.
Tareas prácticas con comandos (y decisiones)
Las container queries son CSS, pero desplegarlas es trabajo operativo: pipelines de build, soporte de navegadores,
pruebas de regresión y perfilado de rendimiento. Abajo hay tareas reales que puedes ejecutar en un repo típico.
Cada una incluye un comando, salida de ejemplo, lo que significa y la decisión que tomas.
Tarea 1: Verificar los objetivos de browserslist (para saber qué prometes)
cr0x@server:~$ cat package.json | sed -n '1,120p'
{
"name": "ui-app",
"version": "1.0.0",
"browserslist": [
"last 2 chrome versions",
"last 2 firefox versions",
"last 2 safari versions",
"not dead"
]
}
Qué significa la salida: Tu transpilación y herramientas CSS tendrán como objetivo esos navegadores.
Decisión: Si debes soportar webviews embebidos antiguos, planea layouts base y evita confiar en container queries para la usabilidad básica.
Tarea 2: Confirmar que tu build CSS no elimina reglas @container
cr0x@server:~$ rg -n "@container" src/styles
src/styles/card.css:11:@container card (min-width: 520px) {
src/styles/widgets.css:21:@container widget (max-width: 479px) {
Qué significa la salida: Tu código fuente contiene container queries donde se esperan.
Decisión: Si la salida del build luego no las incluye, investiga la configuración de PostCSS/minificador y asegúrate de que preserve at-rules desconocidos correctamente.
Tarea 3: Inspeccionar el CSS compilado para la presencia de container queries
cr0x@server:~$ ls -lh dist/assets/app.css
-rw-r--r-- 1 cr0x cr0x 412K Sep 4 11:20 dist/assets/app.css
cr0x@server:~$ rg -n "@container" dist/assets/app.css | head
1842:@container card (min-width: 520px){.card{grid-template-columns:220px 1fr}}
1901:@container widget (max-width: 479px){.widget .meta{display:none}}
Qué significa la salida: Las reglas de container query sobreviven a tu pipeline.
Decisión: Si no están presentes, arregla el build antes de depurar el layout; de lo contrario estarás depurando código que nunca se despliega.
Tarea 4: Validar que tu CSS es sintácticamente correcto (lint rápido)
cr0x@server:~$ npx stylelint "src/**/*.css"
src/styles/card.css
11:1 warning Unexpected unknown at-rule "@container" at-rule-no-unknown
Qué significa la salida: Tu linter no reconoce las container queries (o no está configurado para ellas).
Decisión: Actualiza la configuración de stylelint para permitir @container. De lo contrario, los devs “arreglarán” tu característica eliminándola.
Tarea 5: Comprobar la configuración de stylelint para manejo de at-rules
cr0x@server:~$ cat .stylelintrc.json
{
"rules": {
"at-rule-no-unknown": [true, {
"ignoreAtRules": ["container", "layer"]
}]
}
}
Qué significa la salida: El lint dejará de marcar sintaxis válida de container queries.
Decisión: Haz cumplir esto en los repositorios antes de desplegar container queries ampliamente.
Tarea 6: Rastrear dónde se establece container-type (evitar “contenedor en todas partes”)
cr0x@server:~$ rg -n "container-type:" src | head -n 20
src/styles/card.css:2: container-type: inline-size;
src/styles/widget.css:3: container-type: inline-size;
src/styles/layout.css:5: container-type: inline-size;
Qué significa la salida: Puedes ver qué archivos introducen contenedores de consulta.
Decisión: Si wrappers genéricos de layout son contenedores por defecto, reconsidera. Haz que los contenedores sean intencionales y nombrados.
Tarea 7: Detectar contenedores sin nombre (más difíciles de depurar)
cr0x@server:~$ rg -n "container-name:" src/styles | wc -l
2
Qué significa la salida: Tienes pocos contenedores nombrados en relación con el uso de contenedores.
Decisión: Añade nombres para contenedores que forman parte del contrato del componente o aparecen en múltiples contextos de anidamiento.
Tarea 8: Encontrar umbrales de container query en el código (estándarizarlos)
cr0x@server:~$ rg -n "@container .*min-width" src/styles | head -n 20
src/styles/card.css:11:@container card (min-width: 520px) {
src/styles/widget.css:10:@container widget (min-width: 480px) {
src/styles/table.css:27:@container results (min-width: 640px) {
Qué significa la salida: Existen breakpoints por componente.
Decisión: Si los valores son arbitrarios, crea guías de estados de componente (compacto/regular/espacioso) y alinea umbrales donde tenga sentido.
Tarea 9: Confirmar que el layout base funciona sin container queries (estilo feature-flag)
cr0x@server:~$ rg -n "@container" src/styles/card.css
11:@container card (min-width: 520px) {
cr0x@server:~$ sed -n '1,40p' src/styles/card.css
.card {
container-type: inline-size;
container-name: card;
display: grid;
gap: 12px;
}
Qué significa la salida: La base .card ya es un layout razonable sin la regla de query.
Decisión: Mantén el layout base usable; trata las container queries como mejora, no como prerequisito para legibilidad.
Tarea 10: Usar Playwright para renderizar un componente a anchos de contenedor controlados
cr0x@server:~$ cat tests/card-container-width.spec.js
const { test, expect } = require('@playwright/test');
test('card switches layout at container width', async ({ page }) => {
await page.setContent(`
mediabody
`);
const card = page.locator('.card');
await expect(card).toHaveCSS('grid-template-columns', 'none');
});
cr0x@server:~$ npx playwright test tests/card-container-width.spec.js
Running 1 test using 1 worker
✓ 1 tests/card-container-width.spec.js:3:1 › card switches layout at container width (1.2s)
1 passed (2.0s)
Qué significa la salida: Puedes testear el layout impulsado por contenedor de forma determinista.
Decisión: Añade tests para límites de estado clave para que futuros cambios en el DOM no alteren silenciosamente qué contenedor se consulta.
Tarea 11: Auditar el bundle por reglas duplicadas de container query (bloat de CSS)
cr0x@server:~$ rg -n "@container card" dist/assets/app.css | wc -l
18
Qué significa la salida: Hay muchos bloques de container query para card—posibles duplicados de variantes de componente.
Decisión: Consolida reglas compartidas de container query, o refactoriza variantes para que compongan en lugar de duplicar.
Tarea 12: Comprobar uso accidental de unidades de contenedor cuando se pretendían unidades de viewport
cr0x@server:~$ rg -n "\bcq(w|h|i|b|min|max)\b" src/styles | head -n 30
src/styles/hero.css:14: font-size: clamp(1.2rem, 2.2cqw, 2.0rem);
src/styles/badge.css:8: padding: 0.6cqi 1.2cqi;
Qué significa la salida: Se usan unidades de consulta de contenedor en tipografía/espaciado.
Decisión: Confirma que cada uso tiene el contexto de contenedor correcto y no escalará inesperadamente al anidar. Si dudas, prefiere rem + pasos discretos de container query.
Tarea 13: Confirmar que nadie “amablemente” añadió container-type a wrappers globales
cr0x@server:~$ rg -n "container-type: inline-size" src/styles/layout.css
5:.layout-shell { container-type: inline-size; }
Qué significa la salida: Un wrapper de alto nivel es contenedor de consulta para todo dentro de él.
Decisión: A menos que tengas una razón documentada, elimínalo. Los contenedores globales crean acoplamiento implícito y selección de queries confusa.
Tarea 14: Crear un ligero informe de “contrato de contenedores” para la revisión de PRs
cr0x@server:~$ rg -n "container-(type|name):" src/styles | sort
src/styles/card.css:2: container-type: inline-size;
src/styles/card.css:3: container-name: card;
src/styles/table.css:4: container-type: inline-size;
src/styles/table.css:5: container-name: results;
src/styles/widget.css:3: container-type: inline-size;
src/styles/widget.css:4: container-name: widget;
Qué significa la salida: Un inventario conciso de definiciones de contenedores.
Decisión: Requiere nombres de contenedor para componentes compartidos. Haz que los revisores de PR pregunten: “¿Es este el contenedor correcto y será estable ante refactors?”
Tarea 15: Comprobación rápida de que tu minificador CSS no reescribe las container queries incorrectamente
cr0x@server:~$ node -p "require('fs').readFileSync('dist/assets/app.css','utf8').includes('@container')"
true
Qué significa la salida: Una comprobación booleana básica de que la salida contiene la at-rule.
Decisión: Si es false, detente. Arregla la canalización. No despliegues una característica que tu build elimina.
Listas de verificación / plan paso a paso
Plan paso a paso para adoptar container queries en un código real
-
Elige un componente de alto valor (card, toolbar, resumen de datos, tarjeta de precios).
Elige algo que se reutilice en layouts y actualmente tenga bugs de breakpoints. -
Define el contenedor del componente (normalmente la raíz del componente).
Añadecontainer-type: inline-sizeycontainer-name. -
Escribe primero un layout base que funcione sin container queries.
Hazlo legible, no perfecto. -
Añade 1–3 umbrales de container query mapeando a estados del componente.
Mantén las transiciones significativas (apilar → columnas, ocultar → mostrar, compacto → espacioso). -
Prohíbe contenedores sin nombre en componentes compartidos.
Los nombres previenen cambios accidentales de comportamiento cuando se introducen wrappers. -
Añade pruebas de ancho de componente (visuales o aserciones CSS).
Prueba a anchos alrededor de tus umbrales. -
Inventaría los contenedores a medida que expandes la adopción.
Demasiados contenedores son un riesgo de mantenimiento y rendimiento. -
Despliega gradualmente.
Observa patrones de regresión: layouts anidados, modales, rieles laterales y contextos embebidos. -
Perfila interacciones dinámicas (arrastre resize, abrir/cerrar cajón, scroll infinito).
Si el rendimiento empeora, reduce la granularidad de queries y el alcance de contenedores. -
Documenta el contrato para cada componente:
qué elemento es el contenedor, cuáles son los estados y qué anchos los disparan.
Lista operativa para revisión de PR
- ¿El componente tiene un contenedor de consulta nombrado?
- ¿Los breakpoints están expresados como estados de componente, no etiquetas de dispositivo?
- ¿El layout base es aceptable cuando no aplican las container queries?
- ¿Los umbrales de query son estables (sin flip-flop en los límites)?
- ¿El cambio añade container-type a un wrapper genérico? Si sí, ¿por qué?
- ¿Se usan unidades de container intencionalmente, con un contexto de contenedor conocido?
- ¿Hay al menos una prueba que ejerza los límites de estado?
Preguntas frecuentes
1) ¿Deben las container queries reemplazar por completo a las media queries?
No. Usa media queries para decisiones a nivel de página ligadas al viewport (navegación global, grid general).
Usa container queries para layout interno de componentes. Mezclarlas sin un plan es cómo obtienes “whiplash” de breakpoints.
2) ¿Cuál es lo mínimo necesario para que @container funcione?
Un elemento ancestro con container-type establecido, típicamente inline-size.
Sin eso, no hay contenedor de consulta y tus reglas no coincidirán.
3) ¿Por qué mis container queries funcionan en un sitio pero no en otro?
Probablemente estás consultando un contenedor distinto al que crees (selección por ancestro más cercano).
Nombra tus contenedores y apúntalos explícitamente para evitar cambios accidentales cuando se introducen wrappers.
4) ¿Son seguras las container queries para el rendimiento?
Generalmente sí cuando se usan con intención, pero no son gratuitas.
Muchos contenedores más muchos umbrales pueden aumentar el trabajo de estilo/layout durante redimensiones dinámicos y transiciones de UI.
Perfila las interacciones que importan y mantén las queries toscas.
5) ¿Debería usar container-type: size?
Solo si realmente necesitas consultar ancho y altura. La mayoría de los componentes deberían consultar solo el ancho.
Las consultas de altura son más propensas a crear bucles de retroalimentación y comportamientos con saltos porque el contenido suele determinar la altura.
6) ¿Cómo difieren las unidades de consulta de contenedor (cqw, cqh) de vw/vh?
Las unidades de contenedor son relativas al contenedor de consulta, no al viewport.
Eso es excelente para escalado local, pero confuso en contextos anidados. Úsalas para ajustes pequeños; mantén la tipografía central estable.
7) ¿Cuál es la mejor forma de probar el comportamiento de container queries?
Renderiza el componente a anchos de contenedor controlados en pruebas automatizadas.
No confíes solo en capturas de pantalla de viewport completo. Las pruebas de ancho de componente detectan regresiones de embedding.
8) ¿Cómo manejo navegadores antiguos o webviews embebidos?
Mejora progresiva. El layout base funciona sin container queries; las container queries lo mejoran cuando están soportadas.
Evita polifills frágiles a menos que no tengas alternativa y puedas operar la complejidad.
9) ¿Puedo anidar container queries?
Sí, pero necesitas ser explícito sobre qué contenedor estás consultando.
Usa container-name para evitar sorpresas. Anidar sin nombres es cómo el comportamiento responsivo se vuelve folklore.
10) ¿Cuál es el mayor “gotcha” al que se enfrentan los equipos?
Tratar las container queries como un reemplazo mágico del pensamiento de layout.
Si tu componente es estructuralmente frágil, las container queries solo permitirán que falle en más lugares, con más creatividad.
Conclusión: próximos pasos que puedes enviar
Las container queries son la abstracción correcta para la composición UI moderna: componentes que responden al espacio que se les da,
no a la pantalla que sostienes. Bien hechas, eliminan clases enteras de bugs responsivos.
Hechas sin cuidado, crean otros que son más difíciles de ver y más fáciles de provocar.
Pasos prácticos:
- Elige un componente de alto impacto y mueve su responsividad interna de media queries a un contenedor nombrado.
- Mantén el layout base usable sin container queries. Esa es tu historia de compatibilidad y resiliencia.
- Estandariza estados de componente y umbrales, y escribe pruebas a anchos de contenedor alrededor de los límites.
- Audita y reduce contenedores “ambientales” en wrappers de layout. Los contenedores deben ser intencionales, no contagiosos.
- Usa la guía de diagnóstico rápido cuando algo falle; no adivines qué ancestro es el contenedor.
La meta no es usar la característica CSS más nueva en todas partes. La meta es dejar de enviar UIs que solo funcionan en el único layout que probaste.
Las container queries, usadas con mesura, te llevan ahí.