Curso de CSS / diseño fluido: anchuras relativas, min() y clamp()
Un diseño fluido permite que las dimensiones se adapten al espacio disponible mientras impone límites útiles. Los anchos relativos, max-width y funciones como clamp() pueden mantener el contenido legible sin forzar las mismas dimensiones fijas en cada pantalla.
Distingue el ancho del viewport y el ancho disponible
El área donde se muestra una página web en el navegador se llama ventana gráfica (viewport). Sin embargo, el ancho disponible para las tarjetas dentro del cuerpo puede ser menor que el de la ventana gráfica. Esto se debe a que la tarjeta debe ajustarse al espacio restante excluyendo el margen del contenedor padre, el espacio de otras columnas y el límite máximo de ancho.
El porcentaje en width: 100% utiliza el ancho del área base que rodea el elemento en un diseño de bloque típico. 100vw se basa en el ancho de la ventana gráfica, por lo que incluso si lo colocas dentro de una tarjeta pequeña, puede ser tan grande como toda la pantalla. Cuando se agregan barras de desplazamiento verticales y márgenes exteriores, puede ocurrir desbordamiento horizontal. Para el ancho de los elementos dentro del cuerpo, primero considera el porcentaje o el tamaño automático.
| designación | padres estrechos | padres anchos | Estándar de uso |
|---|---|---|---|
| width: 48rem | Puede ser más grande que los padres | Mantener 48rem | No adecuado como valor predeterminado para contenido que debe adaptarse a una menor anchura |
| width: 100% | Reducido para coincidir con los padres | Continúa aumentando hasta el ancho del padre | Elementos que necesitan llenar el padre |
| width: 100%; max-width: 48rem | Reducido a menos de 48rem | Hasta 48rem | Texto que requiere un ancho de lectura limitado |
| min-width: 48rem | No se reduce por debajo de 48rem | Decidido según diferentes reglas de tamaño | Usar solo cuando hay un tamaño mínimo requerido |
Limita y centra el área de contenido
*, *::before, *::after { box-sizing: border-box; }
.content {
width: 100%;
max-width: 48rem;
margin-inline: auto;
padding-inline: 1rem;
}
Con border-box, el relleno y los bordes se ajustan dentro del ancho declarado. Si la fuente raíz es de 16px y el contenedor padre tiene 390px de ancho, el ancho exterior de este cuadro de contenido es de 390px y su relleno de 16px en cada lado deja 358px para el contenido. Con un ancho de contenedor padre de 1000px, el ancho exterior se detiene en 768px y los márgenes automáticos lo centran. Para más detalles, ver anchura, altura, límites min/max y box-sizing con CSS.
Aplicar content-box al mismo elemento agregará relleno a width: 100%, haciéndolo más ancho que su contenedor. Por otro lado, los márgenes tampoco se incluyen en border-box. Al especificar width: 100% y márgenes fijos en ambos lados juntos, comprueba la suma total. Si min-width y max-width entran en conflicto, comprueba min-width también, ya que el min-width puede hacer que sea más grande.
Usa min() y clamp()
min() selecciona el valor más pequeño entre los candidatos. width: min(100%, 48rem) usa el menor entre el ancho del contenedor y 48rem, por lo que los límites de ancho del 100% y el máximo especificados anteriormente pueden expresarse en una sola declaración.
.content { width: min(100%, 48rem); }
h1 { font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem); }
clamp(minimum, preferred, maximum) usa el valor preferido limitado por el mínimo y el máximo; no calcula una media aritmética. En el título de arriba, rem se basa en el tamaño de fuente raíz y vw se basa en el 1% del ancho de la ventana gráfica. Si el tamaño raíz es de 16px, el mínimo es 24px, el máximo es 40px y el valor preferido es 16px más el 2% del ancho de la pantalla.
| ancho de la ventana gráfica | Calcular valor central | tamaño real del título |
|---|---|---|
| 320px | 16 + 6.4 = 22.4px | Mínimo 24px |
| 600px | 16 + 12 = 28px | 28px |
| 1200px | 16 + 24 = 40px | 40px |
| 1600px | 16 + 32 = 48px | Máximo 40px |
Si haces que el texto del cuerpo dependa únicamente del ancho de la pantalla, puede volverse demasiado pequeño en pantallas estrechas o en situaciones con zoom. Al usar tamaños fluidos en los títulos, un buen punto de partida es tener un límite inferior legible y mantener el cuerpo en un tamaño basado en rem. Incluir rem en la expresión no garantiza por sí solo que el texto se amplíe de forma accesible, por lo que también necesitarás verificar la magnificación real del navegador y la configuración de fuente predeterminada. Puedes revisar el papel de cada argumento en la definición de clamp() y la explicación de accesibilidad de MDN.
Ejecuta el ejemplo de tarjeta fluida e imagen
Guarda el siguiente código como fluid-size.html en UTF-8 y ábrelo en el navegador. La imagen es datos SVG incluidos en el archivo, por lo que no es necesario descargar una imagen separada o una biblioteca externa. Compara el ancho del cuerpo, el número de columnas de la tarjeta y el tamaño del título en una pantalla amplia y en una pantalla estrecha de aproximadamente 390px. Si quieres colocar varias tarjetas de manera flexible, consulta Grid: repeat, auto-fit, auto-fill y áreas con nombre para ver cómo establecer el ancho mínimo para las columnas.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>fluid-size.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; }
.content { width: min(100%, 48rem); margin-inline: auto; padding: 1rem; }
h1 { font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem); line-height: 1.3; }
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: 1rem; }
.card { min-width: 0; padding: 1rem; background: #e8f3fa; overflow-wrap: anywhere; }
.card img { display: block; max-width: 100%; height: auto; margin-bottom: 1rem; }
.token { font-family: monospace; }
</style>
</head>
<body>
<main class="content">
<h1>Size elements to fit the screen and content</h1>
<p>The content is at most 48rem wide and shrinks to fit its parent on smaller screens.</p>
<div class="cards">
<article class="card"><img src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22400%22%20height%3D%22300%22%20viewBox%3D%220%200%20400%20300%22%3E%3Crect%20width%3D%22400%22%20height%3D%22300%22%20fill%3D%22%23287699%22%2F%3E%3Crect%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%23205c32%22%2F%3E%3Crect%20y%3D%22265%22%20width%3D%22400%22%20height%3D%2235%22%20fill%3D%22%239e3131%22%2F%3E%3Ccircle%20cx%3D%22200%22%20cy%3D%22150%22%20r%3D%2270%22%20fill%3D%22%23f6ae4c%22%2F%3E%3Crect%20x%3D%2212%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3Crect%20x%3D%22358%22%20y%3D%22120%22%20width%3D%2230%22%20height%3D%2260%22%20fill%3D%22white%22%2F%3E%3C%2Fsvg%3E" width="400" height="300" alt="Practice drawing with upper and lower bands and center circle"><h2>card with picture</h2><p>The image stays within the card width and preserves its original aspect ratio.</p></article>
<article class="card"><h2>A heading and description that wrap onto several lines</h2><p>Without a fixed height, the card grows as its text gets longer.</p></article>
<article class="card"><h2>Long identifier</h2><p class="token">ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</p></article>
</div></main>
</body>
</html>
El minmax(min(100%, 14rem), 1fr) de la tarjeta utiliza un ancho mínimo predeterminado de 14rem, pero si el contenedor padre es más estrecho, el mínimo pasa a ser el 100% de la anchura disponible del contenedor. auto-fit crea tantas columnas como caben según ese mínimo y colapsa las que quedan vacías, y el ancho restante se divide en columnas de 1fr. Debido al relleno de la tarjeta, el ancho real del texto y las imágenes es menor que el ancho exterior de la tarjeta. No juzgues el número de columnas por el nombre del dispositivo, sino por el ancho disponible para el contenedor padre.
min-width: 0 elimina una restricción de tamaño mínimo que podría impedir que la tarjeta se reduzca. overflow-wrap: anywhere proporciona saltos dentro de una URL larga o un identificador cuando es necesario. Tienen diferentes roles: permitir que la caja se reduzca no hace por sí solo que el texto se ajuste. El ajuste cambia la presentación, no el valor de la cadena copiada.
Prueba un cambio de tamaño a la vez
- Reduce la pantalla a 390px. El texto debe caber dentro de la pantalla, la tarjeta debe ir verticalmente, y las bandas sobre y debajo de la imagen y el círculo en el centro deben ser visibles.
- Cambia solo el ancho de
.contenta48rem. Después de verificar por qué el texto se desborda en la pantalla estrecha, devuélvelo amin(100%, 48rem). - Cambia solo el valor máximo del título a
3remy observa la diferencia en una pantalla más ancha. Calcula el valor preferido para entender por qué este cambio no aumenta el título en pantallas estrechas. Después restaura el máximo de 2.5rem. - Solo elimina
overflow-wrap: anywherede.card. Comprueba si los identificadores largos desbordan y restaura la declaración. Prueba también el tamaño de fuente predeterminado y el zoom del navegador por separado, registrando cada condición.
Antes de insertar overflow-x: hidden, que oculta el desbordamiento, en toda la página, comprueba el ancho, margen, ancho mínimo y cadena. Si solo ocultas el desbordamiento, el contenido o los elementos operativos pueden cortarse sin resolver la causa. Para los principios básicos de la configuración adaptable, también puedes consultar la guía de diseño responsivo de MDN.




