Curso de CSS / consultas de contenedor para componentes reutilizables
Las consultas de tamaño de contenedor permiten que un componente responda al tamaño de un contenedor ancestro elegible en lugar de solo al tamaño de la ventana gráfica. Declara un contenedor de consulta con container-type y luego usa @container para cambiar los estilos de los descendientes al tamaño adecuado.
Compara las condiciones de la ventana gráfica y del contenedor
Incluso si el ancho del navegador es de 1200px, la colocación adecuada variará dependiendo de si la tarjeta está en el área de texto principal de 700px o en el área de la barra lateral de 300px. Es difícil expresar esta diferencia utilizando únicamente consultas de medios CSS y puntos de cambio según el contenido, donde las dos tarjetas comparten las mismas condiciones de la ventana gráfica. Al reutilizar partes, se pueden reducir las reglas de excepción específicas del diseño cambiando su configuración interna según el ancho del contenedor padre.
| división | Criterios de juicio | rol adecuado |
|---|---|---|
| @media | Entorno como el ancho de la ventana gráfica | Número de columnas en la página, ubicación de la barra lateral |
| @container | tamaño del contenedor ancestro seleccionado, etc. | Colocación de imágenes y texto dentro de la tarjeta, espacio entre las partes |
Las consultas de contenedor también comparan el ancho de la expresión condicional en lugar de “colocarse horizontalmente si la pantalla es horizontal.” Cuando la barra lateral alcanza 30rem o más, las tarjetas dentro de ella también pueden colocarse horizontalmente. Si siempre deseas una barra lateral estrecha, también deberías especificar un ancho máximo en el diseño principal.
Declara un contenedor de consulta de tamaño
.slot { container: panel / inline-size; }
@container panel (min-width: 30rem) {
.card { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: 1rem; }
}
container: panel / inline-size declara el nombre panel y la contención de tamaño en línea. En la escritura horizontal, la dimensión en línea es horizontal; la escritura vertical cambia esa correspondencia. Proporciona el ancho del contenedor a través de su diseño de bloque exterior o pista de Grid para que la tarjeta tenga un tamaño significativo para consultar. Consulta fundamentos de Grid: pistas, líneas y colocación.
El padre para evaluar la condición es .slot y el descendiente para recibir el estilo condicional es .card. No intentes aplicar una consulta de tamaño a la misma tarjeta cuyo tamaño consultas: la regla debe actuar sobre descendientes del contenedor elegido. Para evitar el problema de que las condiciones se alternen una y otra vez a medida que cambia el tamaño, las consultas de tamaño operan en relación con los ancestros apropiados.
La contención inline-size hace que el tamaño en línea del contenedor sea independiente de las contribuciones de contenido de sus descendientes. Por lo tanto, un contenedor de ajuste a contenido puede volverse inesperadamente pequeño. Aquí, un bloque o una pista de Grid proporciona su ancho. Usar la contención size también afecta al otro eje y puede colapsar una altura determinada por el contenido, así que elige la contención deliberadamente. Para más detalles, consulta la descripción de container-type de MDN sobre el alcance de la contención de tamaño.
Reutiliza una tarjeta en diferentes anchos de contenedor padre
Guárdalo como container-card.html y ábrelo en tu navegador. El cuadro de color es un elemento de ejemplo que representa el área de la imagen, por lo que no hay un archivo de imagen separado. En pantallas más grandes, separa el texto principal y una barra lateral de hasta 20rem, y en 44rem o menos, coloca las dos áreas en una columna.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>container-card.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
.layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 20rem); gap: 1rem; width: min(100%, 75rem); margin-inline: auto; padding: 1rem; }
.slot { min-width: 0; container: panel / inline-size; }
.card { min-width: 0; padding: 1rem; background: #e8f3fa; overflow-wrap: anywhere; }
.media { min-height: 7rem; background: #287699; }
.card h2 { font-size: 1.25rem; } .card p { margin-bottom: 0; }
@container panel (min-width: 30rem) {
.card { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: 1rem; align-items: start; }
}
@media (max-width: 44rem) { .layout { grid-template-columns: minmax(0, 1fr); } }
</style>
</head>
<body>
<div class="layout">
<main class="slot"><article class="card"><div class="media" aria-hidden="true"></div><div><h2>Card in the main content area</h2><p>The image and text appear side by side when the parent is at least 30rem wide.</p></div></article></main>
<aside class="slot"><article class="card"><div class="media" aria-hidden="true"></div><div><h2>The same card in a sidebar</h2><p>The sidebar in this example stays at or below 20rem even on a wide screen, so the card keeps its vertical layout.</p></div></article></aside>
</div>
</body>
</html>
En un entorno predeterminado con una fuente raíz de 16px, los 30rem de esta consulta de contenedor equivalen a 480px. Si el contenedor .slot del contenido principal en una pantalla grande es de 480px o más, el interior de la tarjeta tendrá dos columnas, y en una barra lateral de hasta 320px, el interior de la tarjeta se dispondrá verticalmente. En pantallas estrechas, a medida que la barra lateral se mueve hacia abajo, su contenedor padre puede volverse más ancho. Por lo tanto, es normal que ambas tarjetas se coloquen horizontalmente en una pantalla de 600px siempre que el ancho del contenedor padre cumpla con las condiciones.
La condición externa de 44rem y la condición interna de 30rem resuelven problemas diferentes. La primera condición determina cómo colocar el área en toda la página, y la segunda condición determina cómo colocar imágenes y texto dentro del espacio dado a cada tarjeta. Incluso si los nombres de los padres son los mismos, cada tarjeta selecciona primero el ancestro elegible más cercano llamado panel y evalúa su tamaño. Si ese contenedor no alcanza el umbral, la consulta no busca otro más lejano que sí lo alcance.
Elige contenedores cercanos o con nombre
Una consulta de tamaño sin nombre selecciona el contenedor ancestro más cercano cuyas condiciones puedan ser consultadas. Incluso si el área externa es amplia, los resultados pueden variar si se agrega un contenedor más estrecho en el medio. Puedes ver esta diferencia por separado guardando el siguiente ejemplo como container-nested.html.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>container-nested.html</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font: 1rem/1.6 sans-serif; color: #243447; }
h1, h2, p { margin-top: 0; } a { color: #145f8f; }
a:focus-visible, button:focus-visible, input:focus-visible { outline: 3px solid #ac4100; outline-offset: 3px; }
main { width: min(100%, 42rem); padding: 1rem; }
.outer { width: 100%; container: outer / inline-size; border: 2px solid #789; padding: 1rem; }
.inner { width: min(100%, 17rem); container-type: inline-size; }
.card { padding: 1rem; background: #e8f3fa; overflow-wrap: anywhere; }
.media { min-height: 5rem; background: #287699; }
@container (min-width: 30rem) {
.card { display: grid; grid-template-columns: 5rem minmax(0, 1fr); gap: 1rem; }
}
</style>
</head>
<body>
<main><h1>Which parent's width is queried?</h1><div class="outer"><div class="inner"><article class="card"><div class="media" aria-hidden="true"></div><p>The nearest inner container has a maximum of 17rem.</p></article></div></div></main>
</body>
</html>
En pantallas anchas, el contenedor exterior es más grande que 30rem, pero el contenedor interior tiene como máximo 17rem. La condición sin nombre selecciona el más cercano por dentro, por lo que las tarjetas se disponen verticalmente. Mantén el otro código y reemplaza @container (min-width: 30rem) con lo siguiente:
@container outer (min-width: 30rem) {
.card { display: grid; grid-template-columns: 5rem minmax(0, 1fr); gap: 1rem; }
}
Ahora seleccionamos el ancestro exterior llamado outer, por lo que la tarjeta se dispone horizontalmente en la pantalla ancha. La tarjeta en sí todavía está dentro del máximo de 17rem, por lo que necesitarás verificar por separado si queda anchura suficiente para el texto dentro de la tarjeta. El nombre no es una propiedad que corrija automáticamente estándares incorrectos, sino una función que especifica qué ancestro usar como estándar. Después de comparar, vuelve a la condición sin nombre.
Diagnostica consultas que no se aplican
- Verifica si el objetivo del selector condicional es un descendiente del contenedor. Verifica que no estés intentando aplicar el mismo estilo al propio padre.
- Verifica el tipo de contenedor del padre y el ancho real del contenido en las herramientas de desarrollo. Distingue la anchura exterior, que incluye relleno y borde, de la anchura de contenido que evalúa la consulta.
- Verifica si se ha creado un nuevo contenedor y, si es necesario, especifica los criterios con container-name.
- Si cambias únicamente container-type a normal, puedes ver la diferencia en que la consulta de tamaño no se aplica. Después de la confirmación, restaura a inline-size.
Mantén una tarjeta vertical legible como línea base, después añade una distribución horizontal cuando se aplique la consulta de contenedor. La línea base también sirve para los navegadores que no admiten la consulta de tamaño. Comprueba la compatibilidad y el comportamiento en los navegadores que los lectores realmente necesitan. Consulta MDN: Consultas de tamaño y estilo de contenedor.




