How can I scale all images to the same dimensional area?

Issue

I’m loading in several images. They are various lengths and widths, but I would like for them all to feel as though they are the same "size". So, if one image is 200×100 and another image is 200×400, I would like for them both to scale in such a way that they take up the same amount of space on the screen. If I fix the width to be 200, then the second element is 4 times the size of the first.

For example:

.my_img {
    width: 200px;
}

produces this behavior

How can I use css to fix the area of an image or other element? Where by area, I mean literally length times width. I would like to load in an image of arbitrary dimensions, and scale it (preserving aspect ratio) so that its area is fixed to be a given value.

Solution

I don’t believe you can do this with CSS. While you can calculate square root with CSS in various ways, getting natural dimensions may be problematic. You’d need that in order to find the smallest image.

For a JavaScript solution, you’d have to first establish the smallest image area, then resize each down according to initial proportion, maintaining aspect ratio.

const images = document.querySelectorAll('img');
let smallestArea = 999999999;

const getSmallestImageByArea = () => {
  images.forEach(image => {
    const width = image.naturalWidth;
    const height = image.naturalHeight;

    if (width * height < smallestArea) {
      smallestArea = width * height;
    }
  });
};

const sizeImagesToSmallestArea = () => {
  images.forEach(image => {
    let width = image.naturalWidth;
    let height = image.naturalHeight;
    const area = width * height;

    if (area > smallestArea) {
      const areaRoot = Math.sqrt(area);
      const proportion = areaRoot / Math.sqrt(smallestArea);
      const aspectRoot = Math.sqrt(width / height);

      width = areaRoot / proportion * aspectRoot;
      height = areaRoot / proportion / aspectRoot;

      image.style.width = width + 'px';
      image.style.height = height + 'px';
    }

    // show hidden images
    image.style.display = 'inline';
    
    console.log('Initial area:', area, '| Final area:', width * height);
  });
};

// wait for images: https://stackoverflow.com/a/60949881/1264804
Promise.all(Array.from(document.images)
  .filter(img => !img.complete)
  .map(img => new Promise(resolve => {
    img.onload = img.onerror = resolve;
  }))).then(() => {
  getSmallestImageByArea();
  sizeImagesToSmallestArea();
});
/* hide images to prevent jumping effect */
img {
  display: none;
}
<img src="https://via.placeholder.com/165x250" />
<img src="https://via.placeholder.com/100x50" />
<img src="https://via.placeholder.com/200x200" />
<img src="https://via.placeholder.com/1900x300" />

Answered By – isherwood

Answer Checked By – Cary Denson (AngularFixing Admin)

Leave a Reply

Your email address will not be published.