0

Similar to this question, I want to create a perfect square grid, but inside of each grid cell, I want to place an image with 100% height.

The problem is because I did the padding-bottom: 100%; height: 0 hack, height: 100% no longer works on the image because the browser thinks the container has 0 height.

How can I set the height of the image to match that of the cell?

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  grid-gap: 4px;
}

.item {
  overflow: hidden;
  position: relative;
  background-color: red;
  width: 100%;
  padding-bottom: 100%;
  height: 0;
}

img {
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  display: block;
  /*height: 100%;*/
}
<div class="grid">
  <div class="item">
    <img src="https://picsum.photos/400/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/500/250">
  </div>
  <div class="item">
    <img src="https://picsum.photos/600/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/400">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
</div>

I should clarify that my intent is to stretch the image height to 100% but maintain aspect ratio. The left and right edges of the image should be clipped as needed, and the image should be centered.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
mpen
  • 272,448
  • 266
  • 850
  • 1,236

3 Answers3

2

You could create a "hidden" cell with a pseudo element (width:0px; height: 0px; padding-bottom: 100%;), overlap it with the real first cell and set all cells to the same height with grid-auto-rows: 1fr; and make the images absolutely positioned.

More in this article: https://medium.com/cloudaper/how-to-create-a-flexible-square-grid-with-css-grid-layout-ea48baf038f3

.grid::before {
  content: '';
  width: 0;
  padding-bottom: 100%;
  grid-row: 1 / 1;
  grid-column: 1 / 1;
}
.grid > *:first-child {
  grid-row: 1 / 1;
  grid-column: 1 / 1;
}
.item {
  overflow: hidden;
  position: relative;
  background-color: red;
  width: 100%;
  /* padding-bottom: 100%; */
  /* height: 0; */
}
img {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  min-width: 100%;
  min-height: 100%;
}
  • Using certain CSS properties like `object-fit` allow for images to "stretch" or be clipped to fit their content box without sacrificing image quality. – Tanner Dolby Jan 10 '21 at 04:36
  • Object-fit should work well if the images have width and height attributes. I updated my answer to create flexible square grid cells which should play nice with object-fit. – Alissa French Jan 10 '21 at 04:46
  • 1
    Yess! This hack maintains the height of the cell so I can stretch the image how I want. Thank you! – mpen Jan 10 '21 at 04:57
2

You could use object-fit: cover and then give the grid items an explicit height so that the replaced content is sized to maintain its aspect ratio while filling the element’s entire content box. object-fit MDN

This would replace your height: 0 and padding-bottom: 100% hack. When using object-fit: cover, one thing to note is that if the object's aspect ratio does not match the aspect ratio of its box, then the object will be clipped to fit.

You could not use object-fit: cover with the following CSS and the images will continue to fill 100% of the grid items height, just without the "clipped to fit" part.

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  grid-gap: 4px;
}

.item {
  overflow: hidden;
  position: relative;
  background-color: red;
  width: 100%;
  height: 18rem; /* vary this to what you need */
}

img {
  display: block;
  max-width: 100%;
  object-fit: cover;
  width: 100%;
  height: 100%;
}
<div class="grid">
  <div class="item">
    <img src="https://picsum.photos/400/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/500/250">
  </div>
  <div class="item">
    <img src="https://picsum.photos/600/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/400">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
</div>
Tanner Dolby
  • 4,253
  • 3
  • 10
  • 21
  • The `object-fit: cover` effect is close to what I'm going for, but the items need to be square. Your change made them a little bit uneven. – mpen Jan 10 '21 at 04:38
  • Ok glad to help. I modified the explicit grid item height to be `18rem` and the grid items are more even squares. Using `20rem` made them a bit too long and not square like, I agree. When you say "uneven" do you mean the width/height for each grid item is uneven? – Tanner Dolby Jan 10 '21 at 04:47
1

You can do it like below:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  grid-gap: 4px;
}

.item {
  background-color: red;
  aspect-ratio: 1; /* square items */
}

img {
  /* no size contribution */
  width: 0;
  height: 0;
  /* */
  /* fill the item space*/
  min-height: 100%;
  min-width: 100%;
  /* */
  display: block;
  object-fit: cover; /* avoid distortion*/
}
<div class="grid">
  <div class="item">
    <img src="https://picsum.photos/400/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/500/250">
  </div>
  <div class="item">
    <img src="https://picsum.photos/600/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/400">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
  <div class="item">
    <img src="https://picsum.photos/300/300">
  </div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415