Lock an Image to a Fixed Aspect Ratio with Percentage-based Padding in Tailwind

Adam Wathan
InstructorAdam Wathan
Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 3 years ago

Right now the card looks great at this screensize but when that is adjusted (and gets larger) you'll notice that the image resolution will stretch to fit the screen. We will want to respect the original aspect ratio of the image so as the image gets wider, it gets proportionally taller.

To respect the original aspect ratio of the image, we'll need to position the image absolutely in a containing div that has its bottom padding set to a percentage. This will fix that div's aspect ratio which in turn will keep the images aspect ratio fixed as well.

Instructor: [0:00] Right now, our card looks great at this particular screen size, but you see that when I resize the view port, the card actually looks really wide and short. That's because we've given this image a fixed height over here. What we really, probably want to do is actually preserve some sort of intentional aspect ratio. As the image gets wider, it also gets proportionally taller.

[0:21] Now, it turns out CSS doesn't have any special feature for giving something an aspect ratio, but we can work around that with a couple interesting tricks. I'll show you how it works. Let's go ahead and resize this, so we have a little bit more room to work on the editor side.

[0:34] What I'm going to do to start is I'm going to add a new div above this image tag to explain how we can actually create a box in the browser that has a fixed aspect ratio. I'm going to start by just creating a div here. We're going to give it a background color, so it's easy to see the shape of this particular box.

[0:52] Right now, it has no height or anything, so it's totally invisible. The trick to getting this whole thing to work is this weird quirk in CSS, where when you set padding on an element to a percentage-based value, that percentage is always based on the width of the element. I'll show you what I mean. Let's add an inline style tag here.

[1:11] I'm just going to add a padding bottom to this div. I'm going to set it to 100 percent. What you'll see here on the right now is that we actually have a perfect square, where the height is exactly equal to the width.

[1:24] If you wanted to create a perfect rectangle where the height is exactly half the width, we could set the padding bottom to 50 percent of the div's width. Now we have this perfect rectangle that's the shape of two perfect squares.

[1:37] Rather than adding an inline style here to give this div the right shape, I think we should extend tailwind's design system to introduce some percentage base padding, so that we can do this with utility classes.

[1:48] Tailwind already includes a bunch of percentage-based widths, like you can see here, like width 1/2, width 1/12, width 11/12, width 3/4, all that stuff already exists. I think a good approach would be to take that same percentage scale that we use for widths and just bring it over so we can use it for padding as well.

[2:06] The easiest way to do that is to head over to our tailwindconfig.js file. Here in the extend section, I'm going to extend tailwind's built-in spacing scale. I already have all of the percentage widths that come with tailwind in my clipboard. I'm just going to drop those in here.

[2:21] We can take a look at what we have. We've got 1/2, we've got 1/3s, we got 1/4s, 1/5s, 1/6s, and 1/12ths. Why don't we try and pick a value that gives us the shape that we're seeing here approximately? Right now, a perfect rectangle looks like it's going to be maybe a little bit too short. Maybe we want something a little bit taller.

[2:39] Why don't we try something like padding bottom two-thirds? We'll get rid of this in-line style and see what the shape of that div ends up looking like. Yeah, I think this will work pretty well for this image.

[2:51] Now the next thing that we need to do is drop this image inside of this div and try and get it to fill up that entire space. Why don't we move the image into the div first and just see what we get out of the box. The thing that's interesting here is that the div now holds the image, but we still see that full shape under the image.

[3:09] That means this div has actually gotten a lot taller than it was originally, and that's because padding, of course, is applied on top of whatever the size of the content inside the container is. This image is taking up a bunch of space in the div, and then we're adding that padding in addition to it. How can we avoid that?

[3:27] One way that we can do that is to give this image a position of absolute, and that tells the browser to basically remove the image from the regular document flow so that it doesn't affect the size or shape of anything around it.

[3:40] When something's positioned absolutely, we can sort of tell the browser where to render it by using utilities like top zero, for example, which will say, render this image zero pixels from the top of the nearest positioned element, is what they call it in CSS. By default, nothing is positioned except the whole viewport or the body element.

[4:00] You see this image actually jumps right to the top of the screen, which isn't what we want. We want to position this image relative to this red box. The way that we can do that is by making this div a positioned element, and we can do that by giving it a position of relative.

[4:15] What relative does is it basically makes it behave exactly the same way it would by default, except now it acts as a positioning reference for any nested absolute positioned elements. Now when we say top zero, it's rendering the image zero pixels from the top of this div. We can also set this to say bottom zero, and now the image will be rendered at the bottom of that div.

[4:36] The contents of a div are always rendered in the top left corner by default. All we really have to do here if we want this image to take up the entire space of this parent div is give it a height of full and a width of full. Now all of a sudden, we have an image that takes up the entire space created by this div.

[4:55] Because of this object cover utility, the image isn't stretched or distorted in any way. Now if we make the browser bigger and maybe switch back to this resizable mode, you'll see that the image actually preserves its aspect ratio no matter how big the card gets.

Ronald Rey
Ronald Rey
~ 4 years ago

I pulled this down locally, removed the classes from the image container and the absolute class on the image itself and can see the exact same behavior around the aspect ratio when resizing the viewport. I even tried in IE11 just in case and even then it seems to still work the same way without the padding + absolute positioning hack. In other words, the snippet below...

    <div>
      <img class="h-full w-full object-cover" :src="property.imageUrl" :alt="property.imageAlt">
    </div>

seems to work the same way to me than what you ended up with in the video. What did I miss when testing? Is there an edge case that this workaround accounts for that I didn't come across?

Awesome series by the way, and loving Tailwind! Keep up the good work! <3

Markdown supported.
Become a member to join the discussionEnroll Today