Aquí tienes el codepen con el código listo para copiar, por si lo quieres implementar en tus proyectos.
Es el resultado que iremos siguiendo durante este artículo.
See the Pen
Image Aspect Ratio CSS by animaticss (@animaticss)
on CodePen.
El aspect ratio o relación de aspecto en castellano, describe la relación proporcional de un elemento entre su ancho y alto.
Se expresa normalmente como `X:Y`
. Siendo `X`
el ancho y la letra `Y`
el alto.
Dicho valor se calcula dividiendo el ancho entre el alto del elemento.
Dos relaciones de aspecto comunes son `4:3`
y `16:9`
, pero hay más.
Te muestro las relaciones de aspecto más comunes ordenadas de menor a mayor según su valor de relación de aspecto.
Y también tenemos la posibilidad inversa de esas relaciones, para imágenes verticales:
El valor que nos interesa es el valor porcentual de la relación de aspecto.
Para obtenerlo, hemos hecho la división del alto entre el ancho y después multiplicamos por 100.
La fórmula matemática sería esta: `(Y/X)*100`
El valor obtenido responde esta pregunta, ¿cuánto de alto tiene un elemento respecto a su ancho?
Es decir, si un elemento tiene `100px`
de ancho y tiene una relación de `16:9`
, este elemento tendrá una altura de `56.25px`
.
Si tiene un aspect ratio en CSS de `1:1`
tendrá una altura de `100px`
.
Ya que su relación es `1:1`
, es decir, `100%`
de alto respecto a su ancho.
Ahora que sabes que es la relación de aspecto, dirás ¿porqué te estoy contando esto y porqué te debería interesar en el desarrollo web front end?
Pues verás, cuando te pasen el diseño de una web, tendrás la maqueta (diseño) con imágenes de prueba y raramente serán las imágenes finales.
¿Y qué ocurre entonces? Que en la maqueta queda muy bonito, pero cuando el cliente decida subir una imagen con una relación de aspecto diferente, aparecerán los problemas.
Veámoslo con un ejemplo.
Ejemplo de grid con imágenes de diferente aspect ratio en CSS
Este es el resultado cuando acabamos el proyecto. Calcado de un diseño que nos han pasado previamente.
Por cierto, el borde rojo que ves está integrado en la propia imagen, lo he añadido para la explicación que haré. Es el límite de la propia imagen.
Vale, ahora llega el cliente con ganas de trastear y pone una imagen diferente en la caja 2.
Y entonces te encuentras esto:
¿Ves? Se ha roto, por así decir.
Rompe la armonía que tenía la web, si esto ocurre, el diseñador y el cliente, irán a por ti y tendrás que huir del país como poco.
Vale que no cunda el pánico, lo que pasa aquí es que las imágenes no tienen el mismo alto para su ancho disponible.
Es decir, tienen una relación de aspecto diferente.
Entonces como ahora mismo tu código simplemente pinta las imágenes, el alto de cada caja puede variar, y al variar, rompe el diseño.
Veámoslo en el modo debug:
La línea negra representa el contenedor total disponible y las líneas verdes representan el espacio reservado para cada ítem.
Las imágenes ocupan lo que deben ocupar en alto para su ancho disponible y entonces, la imagen más alta establece la altura para las demás cajas.
Para corregirlo, lo que haremos será establecer la misma relación de aspecto para todas las imágenes.
Así todas tendrán la misma altura para el ancho disponible que tienen.
Para generar el aspect ratio deseado haremos lo siguiente:
Haremos que las cajas que envuelven las imágenes tengan un espacio reservado con una relación de aspecto concreta, y las imágenes estarán dentro posicionadas de manera absoluta y ocupando el 100% de ancho y alto disponible. Así, estarán delimitadas siempre por el ancho y alto que deseamos.
Añadimos al nodo padre de cada imagen las clases `o-aspect-ratio o-aspect-ratio--16-9`
.
Y a la imagen, la clase `o-aspect-ratio__target`
.
Quedaría así el html:
<div class="c-section__grid-item-wrapper-image o-aspect-ratio o-aspect-ratio--16-9">
<img class="c-section__grid-item-image o-aspect-ratio__target" src="1-debug.jpg" />
</div>
Y el CSS sería así:
// ASPECT RATIO
// o-ar ALIAS
.o-aspect-ratio,
.o-ar{
position: relative;
display: block;
width: 100%;
height: auto;
overflow: hidden;
&::before{
content: "";
display: block;
padding-bottom: 56.25%; // default 16-9
width: 100%;
height: auto;
position: relative;
z-index: 1;
}
&--16-9::before{
padding-bottom: 56.25%;
}
&--8-5::before{
padding-bottom: 62.5%;
}
&--3-2::before{
padding-bottom: 66.66%;
}
&--4-3::before{
padding-bottom: 75%;
}
&--1-1::before{
padding-bottom: 100%;
}
&--3-4::before{
padding-bottom: 133%;
}
&--2-3::before{
padding-bottom: 150%;
}
&--5-8::before{
padding-bottom: 160%;
}
&--9-16::before{
padding-bottom: 177%;
}
&__target{
width: 100%;
height: 100%;
display: block;
position: absolute;
z-index: 2;
top: 0px;
left: 0px;
object-fit: cover;
}
}
Esto es una manera para establecer el aspect ratio:
&::before{
content: "";
display: block;
padding-bottom: 56.25%; // default 16-9
width: 100%;
height: auto;
position: relative;
z-index: 1;
}
Le decimos que ocupe un % de alto respecto al ancho disponible.
El padding bottom es el encargado de darle el tamaño final.
Vale ya está, ya hemos asignado la misma relación a todas las imágenes.
Pero qué.. ¡ahora está todavía peor!
¡La imagen que ha subido el cliente se ve deforme!
Compara las imágenes: ¿notas la diferencia? La de abajo es la correcta.
La que hay en el grid está deformada.
Deja que te explique por qué ha ocurrido.
Ahora mismo, hemos establecido una relación de aspecto en todas las cajas de `16:9`
.
Hemos obligado a todas las imágenes a que se vean con esa relación de aspecto, pero cada imagen tiene su proporción propia.
Entonces lo que ocurre es que se deforman las imágenes que no cumplen con esa proporción.
Todas las imágenes de la maqueta tienen la misma proporción, que era `16:9`
, pero la imagen que ha subido el cliente, tiene una relación de aspecto diferente.
Para evitar este problema, lo que podemos hacer es que las imágenes no se deformen, sino que sólo se recorten si es necesario, con la propiedad`object-fit: cover;`
;
Si no conoces esta propiedad, aquí tienes más información:
Aún así te la voy a resumir:
Esta propiedad define cómo se corresponde el tamaño concreto del objeto con la anchura y la altura usada por el nodo.
Y con el valor `cover`
, la imagen se dimensiona manteniendo su relación de aspecto propia para cubrir toda la superficie de la caja contenedora.
Que en este caso tiene una relación de aspecto diferente.
No se verá el 100% de la imagen porque se recortará, pero se verá bien.
Bueno, si la imagen tiene una relación de `16:9`
no se recortará nada.
Mira comprobémoslo:
Todas estas imágenes tienen una relación de `16:9`
y no se está recortando nada, se ven los bordes aún de la propia imagen.
En cambio la imagen 2, sí que está recortada, no se ven todos los bordes.
Perfecto, ya tenemos el grid adaptado.
Por cierto, si te gusta la metodología usada en el código, se llama BEMIT.
He impartido un curso en Udemy donde te la explico al detalle: curso de BEMIT CSS
Si ya sabes qué es BEMIT y lo estás utilizando, podrías usar este código de la relación de aspecto en tus proyectos como un objeto.
Si no te gusta el nombre usado: `o-aspect-ratio`
, puedes utilizar un alias, por ejemplo: `o-ar`
Usando el alias en el html quedaría así de limpio:
<div class="c-section__grid-item-wrapper-image o-ar o-ar--16-9">
<img class="c-section__grid-item-image o-ar__target" src="2-client-debug.jpg" />
</div>
Te dejo este artículo por si quieres indagar más sobre este tema.
Relación de aspecto – Wikipedia
Bueno, pues ya está.
Si te ha gustado el artículo, apóyame para que traiga más contenido como este.
Dale a like al vídeo y comenta, suscríbete al canal, pero sobretodo, comparte con tus amigos front end, quizás alguno quiera aplicar esta animación en alguna web.
Nos vemos muy pronto.
Un abrazo y … ¡a maquetar!
Si quieres, puedes ver otros artículos como este aquí:
Artículos de animaciones web, tips de CSS y JavaScript
¡Pásate por el discord de maquetadores y saluda o apóyame en Patreon!
Discord de maquetadores web
Patreon