Steve Moretz
Steve Moretz

Reputation: 3128

css or js resize images to fit container

I'm using react + tailwind css

My scenario is : I'll have at most 300 pictures, I shall show these pictures in one screen occupying the most possible space so the images are as big as possible, but all shown in the screen (no overflow).

(Images are at most 300 it could be 10, or 1, for example if it is one it is supposed to fit the screen and occupy the whole space.

For the sake of simplicity the images all have aspect ratio of 1:1

Here's some code I removed the tailwind classes and manually used style because it's easier to understand for the people who haven't worked with tailwind yet.

          <div style={{
                display : 'flex',
                alignItems : 'center',
                justifyContent : "center",
                width : 500,
                height : 500,
                backgroundColor : 'red'
            }}>
                <img key={value} src={`/avatars/1.png`} style={{
                    maxWidth : '100%',maxHeight : '100%'
                }}/>
                <img key={value} src={`/avatars/2.png`} style={{
                    maxWidth : '100%',maxHeight : '100%'
                }}/>
                <img key={value} src={`/avatars/3.png`} style={{
                    maxWidth : '100%',maxHeight : '100%'
                }}/>
                <img key={value} src={`/avatars/4.png`} style={{
                    maxWidth : '100%',maxHeight : '100%'
                }}/>
                <img key={value} src={`/avatars/5.png`} style={{
                    maxWidth : '100%',maxHeight : '100%'
                }}/>
            </div>

In this example I took it only to 5 but it can be changed, thought using maxWidth and maxHeight of 100% would make it magically work, guess I was wrong.

Upvotes: 1

Views: 3129

Answers (2)

digitalniweb
digitalniweb

Reputation: 1142

.img{
    width: 100vw;
    height: 100vh;
    object-fit: cover; // or contain, I never remember these two
}

Upvotes: 1

Rickard Elim&#228;&#228;
Rickard Elim&#228;&#228;

Reputation: 7591

See this more of a proof of concept than a full good solution. My knowledge of React is limited so I will present a regular javascript solution. The code should be self-explanatory, but I will give some pointers in how I tackled this problem.

I assume that the square root is the optimal number of images that can fit in a square, so the bottom row wont be filled most of the times.

I control the size of the images by using flex-basis, adding an aspect-ratio on them, and then scale the image by setting it as a background with background-size: cover.

generateImageArray(amount) should be replaced with an array, either hard-coded or something that you get from the server.

const amountOfImagesRange = document.getElementById('amountOfImages');
const imageContainerDiv = document.getElementById('imageContainer');

amountOfImagesRange.addEventListener('change', () => {
  generateImages(amountOfImagesRange.value);
});

function generateImages(amount) {
  let imageArray = generateImageArray(amount);
  let maxPerRow = getMaxPerRow(amount);
    
  clearContainerDiv();
  
  setNumberOfItemsPerRow(maxPerRow);
  
  fillContainerDiv(imageArray);
}

function randomize(max, min) {
  return Math.floor( max * Math.random() + min );
}

function generateImageArray(amount) {
  const MIN_SIZE = 10;
  const MAX_SIZE = 200;
  let imageArr = [], width = 0, height = 0;
  
  while (amount > 0) {
    amount--;
    width  = randomize(MAX_SIZE, MIN_SIZE);
    height = randomize(MAX_SIZE, MIN_SIZE);
    
    imageArr[amount] = `https://picsum.photos/${width}/${height}`;
    ;
  }

  return imageArr;
}

function getMaxPerRow(num) {
  return Math.ceil(Math.sqrt(num));
}

function clearContainerDiv() {
  imageContainer.innerHTML = '';
}

function setNumberOfItemsPerRow(maxPerRow) {
  imageContainer.style.setProperty('--images-per-row', maxPerRow);
}

function fillContainerDiv(imageArray) {
  for (let imageSrc of imageArray) {    
    const imgEl = document.createElement("div");

    imgEl.style.backgroundImage = `url(${imageSrc})`;
    imageContainer.appendChild(imgEl);
  }
}

generateImages(amountOfImagesRange.value);
:root {
  --image-container-size: 500px;
}

#amountOfImages {
  width: 100%;
}

#imageContainer {
  --images-per-row: 5;
  --flex-basis: calc(100% / var(--images-per-row));

  width: var(--image-container-size);
  height: var(--image-container-size);
  display: flex;
  flex-wrap: wrap; 
  flex-basis: var(--flex-basis);

  outline: 1px solid; 
}

#imageContainer > div {
  width: 100%;
  flex-basis: var(--flex-basis);
  aspect-ratio: 1/1;
  
  background-size: cover;
}
<input type="range" id="amountOfImages" value="25" min="10" max="300">

<div id="imageContainer"></div>

Upvotes: 0

Related Questions