Consultas de contenedor versus consultas de medios: decisiones para la página y decisiones para los componentes
Aprenda cuándo utilizar una consulta de medios y cuándo es más adecuada una consulta de contenedor, a través de ejemplos con tarjetas, paneles de control y unidades que permiten que los componentes reutilizables se adapten.
Fuentes: Container Queries vs Media Queries: How Modern CSS Changes Responsive Design
La mayoría de las soluciones CSS responsivas siguen dependiendo de un único parámetro: el ancho de la ventana del navegador. Esto funciona bien para toda la página, pero falla con los componentes reutilizables, ya que una tarjeta mostrada en una barra lateral y la misma tarjeta mostrada en una columna principal amplia tienen exactamente el mismo área de visualización aunque dispongan de cantidades muy diferentes de espacio. Esta guía muestra cómo las consultas de contenedor cierran esa brecha, en qué casos las consultas multimedia siguen siendo la herramienta más adecuada, y cómo combinar ambas con unidades fluidas para crear un sistema responsivo que sea fácil de gestionar.
Una regla clásica basada en el área de visualización se ve así: una vez que la ventana baja por debajo de un punto de ruptura, la tarjeta apila su contenido verticalmente.
@media (max-width: 768px) {
.card {
flex-direction: column;
}
}
Nada de esto está roto. La debilidad es conceptual: la regla aprende cuán ancha es la ventana, pero nunca cuán ancha es la tarjeta. En una demostración sencilla esos valores se mantienen alineados; en una aplicación llena de cuadrículas, barras laterales y paneles, se separan, y ese espacio es donde aparecen los errores de diseño. Las consultas a contenedores permiten que un componente pregunte “¿Cuánto espacio tengo realmente?” en lugar de “¿Cuán ancha es la pantalla?”.
Por qué un punto de ruptura de vista previa engaña a una tarjeta reutilizable
Tomemos una tarjeta de producto sencilla: una imagen junto a un bloque de texto con un título, una breve descripción y un llamado a la acción. El marcado está dividido en dos fragmentos aquí, pero se trata de un único elemento.
<article class="product-card">
<img src="product.jpg" alt="Product">
<div class="product-info">
<h2>Wireless Headphones</h2>
<p>Noise cancellation with 30-hour battery life.</p>
<button>Buy now</button>
</div>
</article>
La primera fase de estilo suele colocar la imagen y el texto uno al lado del otro con flexbox, y luego se agrega un punto de ruptura de vista previa para apilarlos en pantallas pequeñas.
.product-card {
display: flex;
gap: 1rem;
}
@media (max-width: 768px) {
.product-card {
flex-direction: column;
}
}
Eso parece estar bien hasta que se reutiliza la tarjeta. En una página de escritorio ancha hay mucho espacio horizontal, y el diseño lado a lado se ve adecuado.
Desktop page
┌───────────────────────────────────────────┐
│ │
│ Product Card │
│ ┌──────────┐ ┌─────────────────────┐ │
│ │ Image │ │ Product information │ │
│ └──────────┘ └─────────────────────┘ │
│ │
└───────────────────────────────────────────┘
Si se coloca la misma tarjeta en una barra lateral estrecha, necesita un diseño apilado aunque la ventana siga teniendo el tamaño de escritorio.
┌───────────────┐
│ │
│ Sidebar │
│ │
│ ┌───────────┐ │
│ │ Image │ │
│ ├───────────┤ │
│ │ Info │ │
│ └───────────┘ │
│ │
└───────────────┘
Si se colocan algunas de ellas en una fila del panel de control, cada tarjeta recibe una cantidad diferente de ancho según su columna.
┌───────────────────────────────────────────┐
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │ Card │ │ Card │ │
│ └─────────────┘ └──────────────────────┘ │
└───────────────────────────────────────────┘
Tres ubicaciones, tres anchos diferentes, una vista de pantalla sin cambios. Una regla basada en la ventana no puede distinguirlas, por lo que la tarjeta de la barra lateral sigue estando apretada.
¿En qué son realmente útiles las consultas de medios?
Una consulta de medios evalúa las propiedades del entorno en el que se muestra la página: dimensiones de la vista, orientación, esquema de colores, tipo de puntero, preferencias de movimiento reducido, etc. El caso más conocido es la consulta de ancho.
@media (max-width: 768px) {
...
}
El flujo de información es sencillo: el navegador mide la vista, se verifica si coincide con la consulta y el diseño reacciona en consecuencia.
Viewport
↓
Media Query
↓
Layout changes
Eso hace que las consultas de medios sean el instrumento adecuado para tomar decisiones que realmente corresponden a la página en su conjunto. Un ejemplo típico es una estructura de dos columnas con una barra lateral de ancho fijo:
.page-layout {
display: grid;
grid-template-columns: 1fr 300px;
}
Por debajo de un cierto ancho de ventana, la estructura se reduce a una sola columna:
@media (max-width: 900px) {
.page-layout {
grid-template-columns: 1fr;
}
}
Ese es un uso adecuado de una consulta de medios: si la página tiene espacio para una barra lateral es realmente una cuestión relacionada con la vista. Los problemas surgen cuando el mismo mecanismo decide cómo organiza sus elementos internos un componente individual.
Cómo funcionan las consultas a contenedores
Una consulta a un contenedor permite que un elemento responda al tamaño de un ancestro que se ha marcado explícitamente como contenedor de consulta. Su configuración requiere dos pasos. Primero, declarar el contenedor:
.card-container {
container-type: inline-size;
}
El valor inline-size indica al navegador que los descendientes pueden consultar la dimensión en línea del contenedor, que es su ancho en modos de escritura horizontales. Segundo, escribir una regla para ese contenedor:
@container (max-width: 500px) {
.product-card {
flex-direction: column;
}
}
Ahora la información proviene del contenedor en lugar de de la ventana:
Container
↓
Container Query
↓
Component layout
La tarjeta ya no depende de si el visitante utiliza un teléfono o una pantalla grande; reacciona al espacio que le proporciona su padre.
Un detalle que confunde a la gente
Una consulta de contenedor estiliza a los descendientes del contenedor, nunca al propio contenedor. Por eso los ejemplos siempre combinan un envoltorio (.card-container, .card-wrapper) con un elemento interno (.product-card). Si se aplica container-type a .product-card y luego se realiza una consulta para cambiar su propio flex-direction, no ocurre nada. Mantenga el envoltorio y el componente como elementos separados.
Otro detalle: el modelo de contención inline-size implica que la anchura del contenedor ya no puede derivarse de su contenido. Un contenedor que es un hijo a nivel de bloque en un diseño de flujo normal está bien, ya que su anchura proviene de su padre. Un contenedor que depende del tamaño ajustable, como un elemento inline-block o uno con posición absoluta sin anchura explícita, puede reducirse a una anchura de cero una vez se aplica la contención.
Anchura de la vista previa versus anchura del componente
El contraste se vuelve evidente en un panel de control con una columna principal ancha y una columna lateral más estrecha:
.dashboard {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 1rem;
}
Supongamos una ventana de 1440px. Una regla basada en la vista previa para la tarjeta sería algo así:
@media (max-width: 768px) {
.card {
flex-direction: column;
}
}
En esa ventana, la regla nunca se cumple. Sin embargo, una tarjeta ubicada en la columna más estrecha puede tener solo unos 350px de anchura. La consulta multimedia considera un único valor:
Viewport = 1440px
La tarjeta se encuentra junto con otra:
Component width = 350px
Solo el segundo número describe las condiciones reales de la tarjeta, y solo una consulta de contenedor puede responder a él.
Configuración mínima de una consulta de contenedor
La implementación es breve. Marque el elemento contenedor como tal:
.card-wrapper {
container-type: inline-size;
}
Asigne a la tarjeta una cuadrícula de dos columnas cuando su contenedor tenga al menos 600px de ancho:
@container (min-width: 600px) {
.product-card {
display: grid;
grid-template-columns: 200px 1fr;
}
}
Siempre que sea necesario, utilice un diseño de bloques simple en su lugar:
@container (max-width: 599px) {
.product-card {
display: block;
}
}
El marcado solo necesita el elemento contenedor alrededor de la tarjeta:
<div class="card-wrapper">
<article class="product-card">
...
</article>
</div>
El diseño de la tarjeta ahora proviene de su contenedor, por lo que al mover el envoltorio a otra columna se genera automáticamente el diseño adecuado. Tenga en cuenta que las dos reglas utilizan min-width: 600px y max-width: 599px; con anchuras fraccionarias, un contenedor puede situarse entre esos valores. La sintaxis de rango más reciente, @container (width >= 600px) y @container (width < 600px), evita ese espacio en blanco y es preferible utilizarla en nuevos códigos.
Por qué esto se ajusta a la arquitectura basada en componentes
Las consultas a contenedores son más importantes que una característica nueva típica de CSS, ya que las interfaces frontales modernas se construyen a partir de componentes reutilizables, ya sean componentes de framework en React, Vue o Angular, Web Components sin framework, o los bloques básicos de un sistema de diseño compartido. Ninguno de ellos debería tener que saber en qué área de la página terminará. Considere un elemento user-card. Puede renderizarse en el área de contenido principal:
<main>
<user-card></user-card>
</main>
Puede renderizarse en un apartado lateral:
<aside>
<user-card></user-card>
</aside>
O puede repetirse dentro de una cuadrícula de panel de control:
<div class="dashboard-grid">
<user-card></user-card>
<user-card></user-card>
<user-card></user-card>
</div>
Programar manualmente un punto de ruptura de la vista en ese componente implica asumir algo que no tiene forma de verificar:
@media (max-width: 768px) {
...
}
El número 768 no dice nada sobre el contexto real del componente. Una consulta de contenedor ofrece un contrato mejor: con tanto espacio disponible, se debe utilizar este diseño. Si sus componentes son bloques de construcción independientes del framework, la discusión sobre dónde debe situarse el límite del framework en una pila de interfaz usable es un complemento útil para esta idea.
Permitir que una tarjeta de perfil se adapte a su entorno
Aquí hay una tarjeta de perfil compacta que coloca un avatar junto al nombre y al rol:
.profile-card {
display: flex;
gap: 1rem;
align-items: center;
}
Su contenedor externo se convierte en un contenedor de consultas:
.profile-container {
container-type: inline-size;
}
Cuando ese contenedor tiene 400 px de ancho o menos, la tarjeta apila y centra su contenido:
@container (max-width: 400px) {
.profile-card {
flex-direction: column;
text-align: center;
}
}
En un contenedor espacioso, el avatar se coloca al lado del texto:
┌──────────────────────────────────────┐
│ [Avatar] John Smith │
│ Senior Developer │
└──────────────────────────────────────┘
En situaciones críticas, el mismo componente se reorganiza verticalmente:
┌──────────────────┐
│ │
│ [Avatar] │
│ │
│ John Smith │
│ Senior Developer │
│ │
└──────────────────┘
Ningún observador de cambio de tamaño, ninguna variante “compacta” adicional, ninguna clase activada por la página padre.
Las consultas de medios siguen siendo útiles
Las consultas de contenedor no reemplazan a las consultas de medios; responden a una pregunta diferente. Una forma rápida de clasificar decisiones comunes:
- Colapsar la navegación principal: consulta de medios.
- Eliminar la barra lateral a nivel de página: consulta de medios.
- Cambiar el diseño de una tarjeta entre horizontal y vertical: consulta de contenedor.
- Adaptar un componente reutilizable a su posición correspondiente: consulta de contenedor.
- Ajustar la tipografía en toda la página: consulta de medios.
- Permitir que un widget de panel de control responda al ancho de su columna: consulta de contenedor.
- Cambiar todo el diseño de la aplicación a otro formato: consulta de medios.
Un modelo mental: decisiones globales y decisiones de componentes
La forma más clara de dividir el trabajo es separar lo que decide la página de lo que decide cada componente.
Las consultas de medios se refieren a la ventana de visualización
La pregunta detrás de una consulta de medios es:
"What is the viewport doing?"
Se adecúan a:
- Estructura de la página
- Navegación
- Espaciado global
- Tipografía global
- Cambios importantes en el diseño
Las consultas de contenedor se refieren al entorno del componente
La pregunta detrás de una consulta de contenedor es:
"What is my component's environment doing?"
Se adecúan a:
- Carteles
- Widgets
- Panels
- Componentes de interfaz reutilizables
- Módulos de panel de control
- Componentes del sistema de diseño
Dimensionado con unidades de consulta de contenedor
Las consultas de contenedor no son solo bloques condicionales. CSS también define unidades de longitud en relación con el contenedor de consulta más cercano, por lo que los valores pueden escalar continuamente en lugar de cambiar bruscamente en un punto de ruptura:
.title {
font-size: 5cqi;
}
Aquí cqi representa el uno por ciento del tamaño en línea del contenedor, así que 5cqi corresponde al cinco por ciento de su ancho. El conjunto completo de unidades:
cqw → container width
cqh → container height
cqi → container inline size
cqb → container block size
cqmin → smaller container dimension
cqmax → larger container dimension
Un patrón común consiste en envolver una unidad de contenedor con clamp() para que el valor escale junto con el contenedor pero nunca salga de un rango razonable:
.card-title {
font-size: clamp(1rem, 4cqi, 2rem);
}
El título ahora se escala según el espacio del componente y no de la ventana, algo que las unidades de vista previa como vw no pueden representar. Hay dos consideraciones importantes: si un elemento no tiene ningún contenedor padre de tipo query, estas unidades recurren a unidades más pequeñas de la vista previa, por lo que seguirán generando un valor, aunque no sea el deseado. Además, establecer un límite inferior y superior para rem dentro de clamp(), como se muestra anteriormente, es importante para la accesibilidad, ya que un tamaño de fuente determinado únicamente por el ancho del contenedor no responde a la configuración de tamaño de texto del usuario.
Nombrar contenedores en aplicaciones más grandes
Para una página pequeña, basta con un contenedor anónimo:
.container {
container-type: inline-size;
}
Cuando los contenedores están anidados, una regla simple @container coincide con el contenedor ancestro más cercano, que podría no ser el que se pretendía. La abreviatura container permite asignar un nombre al contenedor junto con su tipo:
.dashboard {
container: dashboard / inline-size;
}
Luego las reglas pueden dirigirse explícitamente a ese contenedor:
@container dashboard (min-width: 700px) {
.widget {
grid-template-columns: 1fr 1fr;
}
}
Compare una condición sin nombre:
@container (min-width: 700px)
con una con nombre:
@container dashboard (min-width: 700px)
La versión con nombre deja claro su intención y sigue funcionando incluso si alguien agrega otro contenedor entre el panel de control y el widget más tarde.
Elija las fronteras del contenedor con cuidado
Las consultas de contenedores son poderosas, pero eso no es motivo para agregar esta declaración a cada elemento:
container-type: inline-size;
Cada contenedor aplica un diseño, estilo y restricciones de tamaño en línea, lo que cambia la forma en que se puede dimensionar ese elemento; por eso los contenedores deben delimitar los límites de los componentes de manera significativa en lugar de distribuirse por todas partes. Considere un panel de control con widgets dentro:
<section class="dashboard">
<article class="widget">
<div class="widget-content">
...
</div>
</article>
</section>
Una elección sensata es hacer que el panel de control sea el contenedor nombrado:
.dashboard {
container: dashboard / inline-size;
}
y dejar que cada widget responda a él. La regla no es “usar consultas de contenedor en todas partes”, sino “usarlas donde el comportamiento dependa del espacio disponible”.
Sustituir puntos de ruptura por puntos de ruptura basados en el contenido
Muchos archivos de hojas de estilo contienen una secuencia de puntos de ruptura para la vista como esta:
@media (max-width: 1200px) {
...
}
@media (max-width: 1024px) {
...
}@media (max-width: 900px) {
...
}@media (max-width: 768px) {
...
}@media (max-width: 640px) {
...
}@media (max-width: 480px) {
...
}
A veces esa estructura vertical está justificada. Con frecuencia indica que los componentes fueron diseñados en función de las anchuras de los dispositivos y no de su propio contenido. Las consultas a contenedores te orientan hacia una pregunta diferente: en lugar de “¿qué punto de ruptura utiliza habitualmente el equipo?”, pregúntate “¿a qué anchura deja de verse bien este componente?”. La respuesta te proporcionará un punto de ruptura basado en el contenido:
@container (max-width: 420px) {
.card {
flex-direction: column;
}
}
Nada de 420px corresponde a un teléfono en particular; es simplemente la anchura en la que esta tarjeta deja de tener espacio. Los puntos de ruptura elegidos de esta manera siguen funcionando con cambios en el diseño y con nuevos dispositivos.
Diseño de componentes que no dependen de su ubicación
Las consultas a contenedores también impulsan a los equipos a crear componentes verdaderamente independientes, cuyo comportamiento es predecible dondequiera que se muestren. Imagina un grupo de botones en un sistema de diseño: podría encontrarse dentro de un formulario en una página:
Page
└── Form
└── Button Group
Dentro de una tarjeta en un panel de control:
Dashboard
└── Card
└── Button Group
o dentro de una tarjeta en un barra lateral:
Sidebar
└── Card
└── Button Group
La vista estándar es idéntica en los tres casos; el espacio no. Con una consulta de contenedor, el grupo se adapta sin necesidad de conocer nada sobre la estructura que está por encima.
Un patrón de tarjeta responsive reutilizable
Aquí hay un patrón completo que puede adoptar directamente. El marcado envuelve la tarjeta en un elemento contenedor; nuevamente, el HTML se muestra en dos partes consecutivas.
<div class="card-container">
<article class="card">
<img src="image.jpg" alt="">
<div class="card-content">
<h2>Performance Dashboard</h2>
<p>
Monitor application performance and infrastructure metrics.
</p>
<a href="#">View dashboard</a>
</div>
</article>
</div>
El contenedor se declara como un contenedor:
.card-container {
container-type: inline-size;
}
La tarjeta comienza como una cuadrícula de una sola columna con una imagen en formato 16:9. Una vez que su contenedor alcanza los 600px, pasa a tener una columna de imagen fija junto al contenido y hace que la imagen sea cuadrada. Las reglas están escritas sin saltos de línea entre ellas, lo cual es CSS válido pero merece ser reformateado al pegarlo en una base de código.
.card {
display: grid;
gap: 1rem;
}.card img {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
}@container (min-width: 600px) {
.card {
grid-template-columns: 200px 1fr;
align-items: center;
} .card img {
aspect-ratio: 1;
}
}
Observe lo que esta hoja de estilo no contiene:
@media (max-width: 768px)
La tarjeta nunca consulta la ventana de visualización. Todo lo que decide se basa en su contenedor.
Combinar consultas de contenedor con una cuadrícula que se ajusta automáticamente
Las consultas de contenedor combinan especialmente bien con una cuadrícula que decide su propio número de columnas:
.dashboard {
display: grid;
grid-template-columns:
repeat(auto-fit, minmax(280px, 1fr));
gap: 1rem;
}
Con repeat(auto-fit, minmax(280px, 1fr)), el navegador coloca tantas columnas de al menos 280px como permite la fila y las estira para llenar el espacio restante. Cada widget recibe entonces su propio contenedor:
.widget-container {
container-type: inline-size;
}
y pasa a un diseño interno de dos columnas cuando su espacio es lo suficientemente amplio:
@container (min-width: 500px) {
.widget {
grid-template-columns: 1fr 1fr;
}
}
El panel de control se adapta a una amplia gama de anchuras sin puntos de ruptura de la vista: la cuadrícula decide cuánto espacio tendrá cada widget, y cada widget decide cómo utilizarlo.
El diseño responsive también es una cuestión de usabilidad
Ajustarse a la pantalla no es lo mismo que ser fácil de usar. Una fila de botones que técnicamente cabe en una tarjeta estrecha puede seguir siendo demasiado compacta y propensa a errores al tocarla. Una consulta de contenedor puede apilar las acciones y estirarlas a toda la anchura cuando la tarjeta es estrecha (la regla está dividida en dos fragmentos):
@container (max-width: 350px) {
.actions {
flex-direction: column;
}
.actions button {
width: 100%;
}
}
Los botones apilados de ancho completo ofrecen objetivos de toque más grandes y reducen los toques accidentales. El texto puede seguir la misma lógica, escalándose dentro de los límites a medida que cambia el ancho del componente:
.card-title {
font-size: clamp(1rem, 4cqi, 1.75rem);
}
Los valores específicos importan menos que el principio detrás de ellos: el comportamiento responsive debe reflejar las condiciones en las que realmente se utiliza un componente, no una suposición basada en el tamaño de la ventana.
Donde las consultas de medios siguen siendo la opción adecuada
Las consultas de contenedor no son automáticamente la mejor opción. La navegación global es un caso claro para una consulta de medios, ya que ocultar el menú completo y mostrar un botón de menú es una decisión relacionada con la estructura general de la página (esta regla también se divide en dos partes):
@media (max-width: 900px) {
.navigation {
display: none;
}
.menu-button {
display: block;
}
}
Las preferencias del usuario son otra categoría completamente distinta. Reducir la animación para quienes han solicitado a su sistema operativo menos movimiento no tiene nada que ver con ningún contenedor:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms;
animation-iteration-count: 1;
}
}
Eso es una preferencia de entorno, que solo puede ser leída por consultas multimedia. El objetivo no es eliminar las consultas multimedia, sino dejar de usarlas para tomar decisiones relacionadas con los componentes.
Un enfoque de tres capas para CSS responsive
En una aplicación basada en componentes, resulta útil pensar en el estilo responsive en tres capas.
Capa 1: respuesta global con consultas multimedia
Las consultas multimedia se encargan de los aspectos que afectan a toda la página:
Page layout
Navigation
Global typography
Major structural changes
Application shell
Capa 2: respuesta de los componentes con consultas de contenedor
Las consultas de contenedor se encargan del diseño interno de las partes autónomas:
Cards
Widgets
Panels
Reusable components
Design-system components
Dashboard modules
Capa 3: comportamiento fluido con funciones y unidades
Cuando no se necesita un punto de interrupción fijo, permita que los valores varíen continuamente mediante funciones y unidades modernas:
clamp()
min()
max()
minmax()
cqi
cqw
Un encabezado, por ejemplo, puede crecer junto con su contenedor dentro de dos límites fijos:
.heading {
font-size: clamp(1.5rem, 3cqi, 3rem);
}
Juntos, estas capas forman un sistema en lugar de un conjunto de parches de puntos de interrupción.
El verdadero cambio es quién toma la decisión
Es tentador resumir las consultas a contenedores como “consultas de media para elementos”. Eso es técnicamente preciso, pero no captura la esencia del asunto. Lo que cambia es el modelo de responsabilidades. En el CSS responsive tradicional, la página dicta efectivamente cómo se comporta cada componente:
Viewport
↓
Media Query
↓
Component
Con las consultas a contenedores, cada componente sigue las indicaciones de su propio contenedor:
Component Container
↓
Container Query
↓
Component
Los componentes que tienen sus propias reglas responsivas son más fáciles de reutilizar, mover, probar de forma aislada y mantener. Ese cambio en la responsabilidad es el beneficio duradero.
Una pregunta para resolver cada caso
Cuando no esté seguro de qué herramienta usar, pregúntese si la decisión de diseño se refiere a la página o al componente. Si concierne a la página, utilice una consulta de medios. Si se refiere al espacio asignado a un componente, utilice una consulta de contenedor. Aplicado a los casos recurrentes:
Should the sidebar disappear?
↓
Media Query
Should this card switch from horizontal
to vertical?
↓
Container Query
Should the navigation collapse?
↓
Media Query
Should this reusable widget change
its internal layout?
↓
Container Query
Puntos clave
- Las consultas de medios describen la vista del usuario y su entorno, por lo que se adaptan a la estructura de la página, la navegación, la tipografía global y preferencias como la reducción del movimiento.
- Las consultas de contenedor describen el espacio que recibe un componente, por lo que se aplican a tarjetas, widgets, paneles y componentes del sistema de diseño.
cqi y cqw, envueltas en clamp() con límites en rem, permiten un tamaño fluido sin sacrificar la configuración del tamaño del texto para el usuario.Lecturas relacionadas
- Propiedades personalizadas de CSS en tiempo de ejecución: Theming, puentes JavaScript y @property — Aprenda cómo las propiedades personalizadas de CSS difieren de las variables Sass y úselas para el theming, efectos controlados por JavaScript, tipos fluidos, variantes de componentes y animaciones tipadas.
- Prevenir el desplazamiento acumulativo de la disposición con fondos de video en Next.js — Aprenda técnicas prácticas de CSS y diseño para evitar que los videos de fondo en Next.js causen desplazamiento acumulativo de la disposición en diferentes dispositivos y velocidades de red.