TransWikia.com

CSS: Maintain aspect ratio in responsive img with max-width and max-height

Stack Overflow Asked by Devabc on November 12, 2021

(Similar questions are already asked at stackoverflow, but this question has more constraints, such as both a specific max-width, max-height, a required specific height and width, and no layout shift.)

Problem:

I want to have a responsive image with the following constraints:

  • max-width: 100%, so that it doesn’t overflow to the right, and that it is responsive when reducing the screen width.
  • max-height: 200px, so that large images are reduced in rendered dimensions.
  • height and width html attributes set, so that the browser can precalculate the required image dimensions, so that the layout doesn’t shift/move elements beside/below the image, while the image is loading. (To reduce the cumulative layout shift.)
  • image aspect ratio should stay 1:1
  • no extra margins should be created around the image
  • the image should be rendered with a plain html img tag, not with css background-images
  • the image should not be rendered in a larger dimension than its original dimension

How can I achieve this with CSS?

(If CSS cannot achieve this, then maybe in JavaScript?)

What I tried

I tried several CSS features, such as object-fit and max-width: 100% etc, but I always get at least one of the contraints failing while trying to fix another constraint. For example, object-fit creates margins/paddings for the image when it’s reduced in size when the screen size reduces, as if the image border isn’t reduced. This is demonstrated in the following code:

https://codepen.io/Devabc/pen/mdVvyKq

/* Should appear to the right of the Wombat */

.beside {
  float: left;
  background-color: lightgreen;
  border: 1px solid;
  height: 200px;
  width: 100px;
}


/* Should appear below the Wombat */

.below {
  background-color: red;
  border: 1px solid;
  width: 100px;
  height: 300px;
  clear: both;
}

img {
  display: block;
  float: left;
  max-width: 100%;
  max-height: 200px;
  border: 1px solid;
  
  /* Without this, aspect ratio is not normal. 
But with this, it creates an unwanted margin. */
  object-fit: scale-down;
  object-position: left;
}
<img 
height="533" 
width="799" 
src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Vombatus_ursinus_-Maria_Island_National_Park.jpg/800px-Vombatus_ursinus_-Maria_Island_National_Park.jpg" 
/>

<div class="beside">This text should be directly to the right of the Wombat, without any margin between the Wombat and this text.</div>

<div class="below">This text should be directly below the Wombat, without any margin between this and the Wombat. 
The dimensions of the original Wombat img are:
width: 799px, height: 533px</div>

(The green text should be to the right of the Wombat, without margin. But object-fit causes a padding/margin to appear with the length of the original image.)

It’s feels almost as if this isn’t possible with CSS, even though these requirements shouldn’t be too much to ask nowadays, with responsive design being important.

How can I fix this with HTML/CSS?

3 Answers

I've been struggling with this for years on end, but just today I figured a way to do it when you know the image's aspect ratio, hope it helps:

Start by defining a --img-ratio CSS custom property in the img element corresponding to the image's height / width ratio.

<!-- example of a square image (height / width = 1) -->
<img src="..." style="--img-ratio: 1" />

Knowing that our desired max-height is 200px (or you could go with a generic --max-height), we know 2 variables of the equation:

ratio = height / width
width = height * ratio

Applying this:

img {
  --max-height: 200px;
  /* Set a baseline width for your element */
  width: 100%;
  /* And limit it with our function above */
  max-width: calc(var(--max-height, 200px) * var(--img-ratio, 1));
}

And there we go! This should work to limit the height without extra margins even in complicated flex layouts.

Let me know if this answer is unclear, hope it helps ?

PS: If you can't know the ratio of the image beforehand, than maybe JS is indeed your only option - I'm yet to find an alternative ?

Answered by Henrique Doro on November 12, 2021

If CSS cannot achieve this, then maybe in JavaScript?

I wouldn't solve this with JavaScript. I understand you want to use width & height on img elements to mitigate content layout shifts, but in this case since you must have a max-height of 200px on the image, it will cause issues on images with larger natural width. The space you see between the green text & the Wombat is not margin or padding, it is that actual content width which you have defined as 799px.

You can solve this with a bit of preparation on the data you wish to present to the user. Prepare your width as you would expect what your image width would be. width=799 in this case is unrealistic because the image will not respond as far as that because of the max-height:200px limitation - same case with height=533. The whole point of using static measurements such as unit pixels is you are already declaring that this X element will just take Y space.

<img 
    height="200" 
    width="300" 
    src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/Vombatus_ursinus_-Maria_Island_National_Park.jpg/800px-Vombatus_ursinus_-Maria_Island_National_Park.jpg" 
/>

Answered by 95faf8e76605e973 on November 12, 2021

If your problem is that your webpage/website is not responsive, so I would suggest you to use Viewport Units like vw for width and vh for height instead of px or % for all your elements including border and font-size because it will help you make your webpage/website responsive.

It should solve your issue but if it doesn't let me know in the comments, I will try my best to help you.

Answered by shubh1834 on November 12, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP