Curso de CSS / imágenes y vídeo adaptables: aspect-ratio y object-fit

Los medios responsivos necesitan tanto un tamaño de elemento sensato como una regla deliberada para ajustar su contenido. aspect-ratio ayuda a establecer las proporciones de un cuadro, mientras que object-fit: cover o contain determina si su contenido llena el cuadro con recorte o cabe entero conservando su proporción.

Distingue dimensiones intrínsecas y tamaño de visualización

Si el original es 400×300, la proporción es 4:3. Si el ancho de visualización es 288 px y se mantienen las mismas proporciones, la altura de visualización es 216 px. El ancho y alto en HTML proporcionan información sobre el tamaño y la proporción de la imagen, y CSS controla el tamaño que se mostrará en la página. En lugar de resolver el problema borrando la propiedad de tamaño en el HTML, verifica qué valor está siendo sobrescrito en CSS.

img { max-width: 100%; height: auto; }
/* Instead of forcing the small original size to grow, it is reduced to fit the parent. */

max-width: 100% es un límite superior que evita que se haga más ancho que su contenedor y no aumenta incondicionalmente el original pequeño. width: 100% es una especificación que llena el ancho del contenedor, por lo que puede ampliarse más allá del original. La claridad de la foto y el tamaño de descarga son asuntos separados. Puedes descargar archivos grandes incluso si parecen pequeños con CSS, y cuando usas srcset · sizes, el navegador selecciona una imagen entre los candidatos, por lo que debes verificar el tamaño de visualización en la pantalla y el archivo realmente seleccionado.

Usa aspect-ratio para el dimensionamiento automático

aspect-ratio: 16 / 9 utiliza la proporción de 16 de ancho por 9 de alto para calcular el tamaño. Si el ancho es de 288px, la altura es de 162px. Al menos un tamaño debe ser automático para que se puedan realizar cálculos proporcionales, y si tanto el ancho como la altura son fijos, ese tamaño fijo tiene prioridad incluso si especificas esta propiedad. También puedes consultar las condiciones de cálculo del tamaño de la relación de aspecto de MDN.

.thumbnail { width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }

La guía de alineación y tamaños flexibles con Flexbox explica cómo la alineación stretch puede igualar alturas en una línea flex. Para calcular automáticamente la altura al colocar imágenes con diferentes ratios originales una al lado de la otra, consulta también el align-items: flex-start del padre o el align-self del elemento. Si la proporción se siente igual después de cambiar solo la altura a auto, la regla de alineación del padre puede ser la causa.

En la práctica, el box-sizing se unifica como border-box. Al agregar bordes o relleno, se vuelve importante medir el tamaño y las proporciones de la caja. Las imágenes en los ejemplos de comparación a continuación no tienen bordes ni relleno para evitar confusiones.

Compara el comportamiento de ajuste y recorte

valor del atributo proporción original área de visualización detalle
fill Puede expandirse para ajustarse al área Llena el área Distorsión posible dependiendo del original
cover mantener Rellenar sin espacio vacío Si la proporción es diferente, algunas partes se recortan.
contain mantener Ajustar para que quepa todo Si la proporción es diferente, queda espacio vacío

Ajustar una imagen 4:3 en un recuadro 16:9 con cover recorta la parte superior e inferior. La posición centrada divide el recorte entre ambas; object-position: center top conserva la parte superior y recorta más abajo. Comprueba el contenido importante en los bordes antes de elegir un recorte. Los fondos CSS usan opciones de ajuste relacionadas, pero tienen un rol diferente de contenido y accesibilidad que las imágenes HTML. Consulta Colores e Imágenes de Fondo en CSS: cover y contain .

El siguiente esquema ilustra la misma imagen de práctica geométrica en su proporción original, con cover, con contain y con cover alineado arriba. Compara las bandas de borde verdes y rojas y el espacio vacío a los lados. El círculo central sigue siendo visible en estos ejemplos, por lo que las bandas de borde facilitan identificar el recorte. El ejemplo completo en HTML que aparece después te permite reproducir la comparación.

La imagen 4:3 se ve completa con su proporción original. cover centrado recorta las bandas superior e inferior; contain mantiene toda la imagen y deja espacio a los lados; cover alineado arriba conserva la banda verde.

Ejecuta la comparación de las cuatro imágenes

Guárdalo como image-ratio.html y ábrelo. La imagen original se incluye como datos SVG dentro del archivo, por lo que no se necesita ninguna imagen externa. Los atributos width y height de cada imagen conservan las dimensiones originales de 400×300. Las reglas CSS determinan el tamaño mostrado y la proporción de su caja.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>image-ratio.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%, 65rem); margin-inline: auto; padding: 1rem; }
.gallery { display: flex; flex-wrap: wrap; gap: 1rem; align-items: flex-start; }
.sample { width: min(100%, 18rem); margin: 0; }
.sample img { display: block; width: 100%; height: auto; background: #e2e2e2; }
.sample p { margin: .5rem 0 0; } .cover, .contain { aspect-ratio: 16 / 9; }
.cover { object-fit: cover; } .contain { object-fit: contain; }
.top { object-position: center top; }
</style>
</head>
<body>
<main><h1>Compare the size and cropping of the same picture</h1><div class="gallery"><div class="sample"><img class="" 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="Top green band, bottom red band and center orange circle"><p>Original 4:3</p></div>
<div class="sample"><img class="cover" 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="Top green band, bottom red band and center orange circle"><p>16:9 cover, center</p></div>
<div class="sample"><img class="contain" 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="Top green band, bottom red band and center orange circle"><p>16:9 contain</p></div>
<div class="sample"><img class="cover top" 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="Top green band, bottom red band and center orange circle"><p>16:9 cover, top</p></div>
</div></main>
</body>
</html>
  1. En pantallas anchas, asegúrate de que el ancho de cada imagen esté limitado a 18rem. Con una fuente raíz de 16px, tiene un ancho de 288px, la imagen mostrada en 4:3 mide 216px de alto y las cajas de 16:9 miden 162px.
  2. Cambia solo la altura de .sample img a 300px. Incluso si se aplica la proporción 16:9, verifica que el área sea de 288×300px debido a la altura fija y restáurala a auto.
  3. Cambia solo el align-items de .gallery a stretch. Asegúrate de que la altura del contenedor de la misma línea sea la misma, pero se mantengan las proporciones de la imagen dentro del contenedor, y vuelve a flex-start. En este ejemplo, el elemento Flex es un contenedor de muestra, no una imagen. En configuraciones donde las imágenes se colocan directamente como elementos Flex, la altura automática puede aumentar, por lo que se debe verificar la alineación.
  4. Cambia solo object-position de .top a center bottom. Esta vez, asegúrate de que la banda roja permanezca y la banda verde se corte, y luego restaura center top.

El SVG en el ejemplo también tiene la característica de mantener las proporciones de las formas. Si el área de visualización de un elemento de imagen es incorrecta y crea espacio vacío, el círculo no necesariamente se distorsionará. En lugar de solo mirar la forma, verifica el ancho y la altura del elemento img en las herramientas de desarrollo.

Redimensiona el contenido de video dentro de su cuadro de visualización

En el ejercicio siguiente, se muestra un video silencioso de 400×300 creado para esta lección con object-fit: contain dentro de una caja de 16:9. No hay información de audio ni subtítulos en el video, solo el movimiento del círculo naranja, que se utiliza para verificar los espacios superior, inferior y laterales, así como las operaciones de reproducción. La dirección del archivo de video WebM para práctica está incluida en el ejemplo. En un entorno sin red, descarga previamente este archivo y colócalo en la misma carpeta que el HTML, reemplazando la dirección de origen con el nombre del archivo.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>video-ratio.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%, 34rem); margin-inline: auto; padding: 1rem; }
video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: contain; background: #111; }
</style>
</head>
<body>
<main><h1>Video display ratio</h1>
<p id="video-description">This silent sample video shows an orange circle moving on a blue background. Play and pause it to compare aspect ratios.</p>
<video controls preload="metadata" width="400" height="300" aria-describedby="video-description">
  <source src="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm" type="video/webm">
  <a href="https://www.codingfactory.net/wp-content/uploads/css-media-ratio-motion-v1.webm">Download the sample video</a>
</video></main>
</body>
</html>

El atributo controls permite al usuario utilizar operaciones del navegador como reproducir/pausar, y preload="metadata" es una pista que solicita que se lea la información meta antes de la reproducción. El método real de descarga lo determina tu navegador. Dado que no incluimos reproducción automática, presiona el botón de reproducir para confirmar. Si solo cambias object-fit a cover, puedes ver la diferencia en que el área permanece igual y el contenido en la parte superior e inferior se recorta. Después de la confirmación, restáuralo a contain.

object-fit ajusta el contenido en elementos reemplazados como imágenes y videos. No redimensiona el contenido de un iframe de video incrustado de la misma manera: dale a ese iframe un contenedor con proporciones adecuadas y ajústalo dentro del contenedor. A diferencia de este ejemplo decorativo silencioso, un video con audio significativo necesita alternativas apropiadas, como subtítulos. Ver MDN: object fit, MDN: video.