Maintaining image aspect ratios

Gregor on Apr 2

This week's post is a short one, but a useful trick as to how to achieve that holy grail of client requests - responsive images that maintain their aspect ratio rather than cropping to something undesired.

So what's the problem here? You drop in an image with the img tag, set it to be width: 100%; of its parent container .. and there we go.

Well, not always.

We often want to use the background-image css property on elements instead of an img element sitting in the DOM. A good example of this is when we're building elements where the client can edit / upload the content that will be used. We know our clients are human, so we don't expect the image assets they upload to always be exactly the same size. (Team members get different memos, the photographer cropped them differently.. the list goes on). A layout cannot break just because an image is the wrong size. In this way we often use the background images of elements and the background-size: cover; and background-position: center center; property to ensure a nice even crop and good ol' centering. This can also help when you have been working on one assumption with assets, and then the client suddenly says 'actually, can these crop square?'

But hey. We have a problem. An element will not take the height of a background image. Therefore when we are using a grid-column layout from a framework, such as our preferred tool of choice, Foundation, all that would happen is we get a grid of flat-pancake div elements that have the right width but no height. We could of course set a fixed height that adjusts with media queries, but often we want to keep the fluid scaling that a framework provides.

The fix? We create a transparent .png image that has the ratio we wish to maintain. Ideally this file should be as small as possible and so as small an image as possible. A typical layout with this structure would look something like this:

1
2
3
<div class="image" style="background-image: url('img/the-main-image.jpg');"> 
  <img src="img/transparent-ratio-image.png" /> <!-- maintains aspect ratio -->
</div>

Ensuring that the css (in our case we use scss) of the element holding the background image and the img element is something like this:

1
2
3
4
5
6
7
8
  .image {
    width: 25%;
    float: left;
    background-size: cover;
    background-position: center center;
    
    img { width: 100%; } // ensures transparent image fills parent and pushes height down appropriately
  }

I have created a demo of this here - feel free to fork it and / or comment below if you have any suggestions for why this method has / has not helped you.