Forcing image aspect ratio via CSS

24 Feb 2017

Imagine we want to show a list of images:

1
2
3
4
5
<div class="image-container">
  <div><img src="http://dummyimage.com/200x200" /></div>
  <div><img src="http://dummyimage.com/200x200" /></div>
  <div><img src="http://dummyimage.com/200x200" /></div>
</div>

These will be well aligned if we use some CSS and flex:

1
2
3
4
5
6
7
8
9
.image-container {
  display: flex;
  flex-direction: row;
}

.image-container > div {
  margin: 0 10px;
  width: 100%; /* Flex takes care of this */
}

This code is acceptable for images that have the same aspect ratio, this is, the same ratio between its width and height (200x200px in the example above). If we change the images’ dimensions the result will be different:

1
2
3
4
5
<div class="image-container">
  <div><img src="http://dummyimage.com/300x200" /></div>
  <div><img src="http://dummyimage.com/200x300" /></div>
  <div><img src="http://dummyimage.com/300x400" /></div>
</div>

There are various solutions to this problem:

  • Resize every image by hand.
  • Implement a server-based image resizing algorythm (what about the processing time?).
  • Use just CSS and the padding-top technique as seen in sitepoint.com.
  • Use just CSS to force images to keep their aspect ratio (cleaner solution that the padding-top one IMO).

To keep the aspect ratio, we need images to have a <div> parent with position: relative, which is the one that will be in charge of having the necessary space so that the photo is embedded inside. A great use for this is in card elements, where the image container is preset with a fixed width/height or responsive measurements. Inside this <div> will be the image tag with position: absolute, being centered with the top, bottom, left, and right properties set to 0 and margin: auto, making the properties max-width and max-height the ones that define the width and height of the image. Basically we are forcing the image to “grow” from the center of its parent until one of the limits is reached (width, height, or both).

Let’s see it in action:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.image-container {
  display: flex;
  flex-direction: row;
}

.image-container > div {
  margin: 0 10px;
  width: 100%;
  height: 180px; /* We have set a 180px height as an example */
  background: white; /* We have set a white background to see the image container width/height */
  position: relative;
}

.image-container > div > img {
  position: absolute;
  display: block;
  max-width: 100%;
  max-height: 100%;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
}

We can see that the aspect ratio of the images are being kept, and they automatically place themselves in the optimum position without being wider or longer than their parent element, neither lengthen, flatten, or lose viewing areas, and remarking that it is a solution where the size of the main container doesn’t matter, so it can be used for any responsive view.

View the demo code on JSFiddle.