5

To have responsive images that scale down proportionally on a small screen, I currently use max-width: 100%; (or a fixed max width). As opposed to specifying a fixed size, this has a terrible downsize in that when the page is loading, the browser allocates no space for the image and can only do that after it starts downloading it. This causes a lot of layout reflows and a bad experience before all images are loaded.

This seems like it could be easily fixed - after all, I just have to tell the browser what the real size is so that it can figure out the aspect ratio and the final size before downloading it. First, I was wondering if that's what the width and height html attributes are for, but I know that that's not their purpose as they can be used to rescale the image and change the final size.

What I really want is something like "srcwidth" and "srcheight" that would tell the browser the actual size of the image file so that it doesn't have to load before knowing the aspect ratio to make use of the max-width styling. But from what I could find, there is no such thing like these attributes. Is there really no way to achieve this?

I tried using the actual width and height html attributes in this way and then overriding it with CSS, but browsers simply don't care about that.

FluffyKitten
  • 13,824
  • 10
  • 39
  • 52
Neme
  • 492
  • 3
  • 14
  • Are you using Bootstrap or just CSS and HTML only? – Tes3awy Aug 24 '17 at 19:51
  • Yes, I'm using bootstrap, but haven't looked into their image classes. – Neme Aug 24 '17 at 19:52
  • Simply, you can use `.img-fluid` in your `img` tag. It will take care of the image size on all screens. If you are using BS3 the class is `.img-responsive` – Tes3awy Aug 24 '17 at 20:09
  • That doesn't solve anything. I'm doing the same thing with my own styling right now. – Neme Aug 25 '17 at 19:58

1 Answers1

10

The most common way I've seen this addressed is to put all your images in containers and use the padding-bottom property to "pre-allocate" the height.

<div class="responsive-container">
    <img src="image.jpg"/>
</div>

To do this, you need to know the aspect ratio of the image to calculate the padding.

Using the Aspect Ratio to work out the height

For example, for an aspect ratio of 16:9 (e.g. 800 x 450px) the height is 56.25% of the width so that will be the value for the padding.

.responsive-container {
    width: 100%;
    padding-bottom: 56.25%; /* 9/16 = aspect ratio of image */
    position: relative;
    height: 0;
    overflow: hidden;
}

.responsive-container img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
}

Different Aspect Ratios

If your images will have different aspect ratios, but you will still know then ahead of time, you set up different classes for each, e.g.

.responsive-container {
    width: 100%;
    position: relative;
    height: 0;
    overflow: hidden;
}

.ratio-16-9{
    padding-bottom:56.25%; /* 9/16*100 */
}

.ratio-4-3{
    padding-bottom:75%; /* 3/4*100 */
}

.ratio-1-1{
    padding-bottom:100%; 
}

And to use it in the html:

<div class="responsive-container ratio-16-9">
    <img src="image.jpg"/>
</div>

Calculate height dynamically

Finally, if you want the CSS to calculate the height dynamically for each image, you can use CSS calc() to calculate the height like this:

calc((image_height/image_width)*100%)

So your CSS would be: .responsive-container { width: 100%; position: relative; height: 0; overflow: hidden; }

And you use it like this:

<div class="responsive-container" style="padding-bottom: calc((426/640)*100%);" >
    <img src="image.jpg"/>
</div>

References

FluffyKitten
  • 13,824
  • 10
  • 39
  • 52
  • Thanks, I will have to go with the third option since there's not a fixed set of aspect ratios, it could be arbitrary (they're user uploaded images). I will need to use the inline styles but now I'm thinking I don't need calc at all, I can just calculate the percentage on the server side. Is there any difference between the `position: absolute;` and the `height: 0;` solution? – Neme Aug 25 '17 at 20:14
  • It's still a hack but what did I expect... this is html & css. – Neme Aug 25 '17 at 20:16
  • @Neme "Is there any difference between the position: absolute; and the height: 0; solution?" - You need to use the `.responsive-container img` CSS for all the solutions to position it properly in the container... sorry if that wasn't clear. I think the issue is that HTML & CSS were developed initially for a *very* different web than we have now, so it was never designed for the complexities of today's requirements, especially responsiveness. It wasn't designed for that & has had to be be adapted to keep up, which makes it a bit "hack-y" – FluffyKitten Aug 25 '17 at 20:50
  • Yes but you provided two different CSS styles that achieve the same thing. I could either do (`.responsive-container { position: relative; }` and `img { position: absolute; top: 0; left: 0; }`) or (`.responsive-container { height: 0; overflow: hidden; }`) ... but I think they work in the same way because making the `img` position absolute basically makes the container have 0 height as it stops affecting the layout. – Neme Aug 25 '17 at 20:58
  • Sorry if I'm wrong and you meant to combine them. They both work independently for me. – Neme Aug 25 '17 at 21:01
  • @Neme ah sorry, I misunderstood what you were asking. There's no real dfiference, they will have the same result because they're both essentially the same, but just relying on default values instead of explicitly setting them. They're just different because I compiled them from different sources. For completeness, they should probably both explicitly set the same values so its clear... I'll update my answer. – FluffyKitten Aug 25 '17 at 21:04
  • @Neme And yes, you are right that the abolute positioning of the img element causes the container to have 0 height. – FluffyKitten Aug 25 '17 at 21:05
  • 1
    If anyone is interested, this is how I did it on the server (ASP.NET) without using calc: `
    `
    – Neme Aug 25 '17 at 21:11
  • PHP would be a bit more complicated because you have to get the attributes first, but the same logic: ` ` Handy to have these here for reference, but I won't update the answer because there are so many potential languages, and the question is tagged `html`and `css` so best to stick with a pure HTML/CSS answer. – FluffyKitten Aug 25 '17 at 21:21
  • 1
    Yes of course I already have the size stored in the database... But one more thing about your solution, in the 3rd option you set `padding-bottom` on the img, but I think it has to be on the div, it doesn't work this way. – Neme Aug 25 '17 at 21:26
  • Pinterest uses the pre-calculated on the server margin-bottom inline style method, so even though a hack, it looks like it works well. So just wrap your images with the responsive-container class as above, and define the margin-bottom inline for each container element in your content management software using height/width*100. – otterslide Sep 07 '17 at 16:41