3

I am looking for a way to automatically generate a grid, that always fills the available space, while shrinking the items until another item can be added.

Most responsive grid implementations use something link this:

grid-template-colums: repeat(auto-fill, minmax(120px, 1fr));

This works fine, except, that it uses the minimum value as the default image size, which results in interpolation of the images inside the grid. I want to do the opposite — set a max-width and shrink the images if necessary.


Let’s say my grid items should have a max-width of 400px. Here are some of the values, that I want to get:

400px available space: One image with a width of 400px
402px available space: Two images with a width of 201px
800px available space: Two images with a width of 400px
and so on …

Essentially I want to clamp my image between 200px and 400px and always use the biggest value possible. I guess I need something like this:

min(max(200px, 1fr), 400px)

The only way I was able to achieve this so far, was by generating some media queries.

/* This example adjusts items to a max-width of 400px with a 10px grid-gap.*/

@media (min-width: 401px) {
  .grid {
    grid-template-columns: repeat(auto-fill, calc((100% - 10px) / 2));
  }
}
@media (min-width: 811px) {
  .grid {
    grid-template-columns: repeat(auto-fill, calc((100% - 20px) / 3));
  }
}

I have written a Sass mixin to make this process more flexible, but this solution comes with some draw-backs:

  • You have to generate an arbitrary amount of queries in order to handle multiple screen sizes, which probably results in dead-code
  • You have to know the available space of the grid container for the media queries (or the used space to calculate the available space)

I am looking for a way that does not have these drawbacks.


Edit:

Here is a CodePen of my current code. It should be easier to understand what I want to do, if you play around with it.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Afterlame
  • 1,188
  • 2
  • 13
  • 32

1 Answers1

2

Your media queries solution may be your best option, at this point.

Currently, CSS Grid does not provide for flexible minimums.

From the spec:

minmax(min, max)

Defines a size range greater than or equal to min and less than or equal to max.

If max < min, then max is ignored and minmax(min,max) is treated as min.

As a maximum, a <flex> value sets the track’s flex factor; it is invalid as a minimum.

Note: A future level of this spec may allow <flex> minimums, and will update the track sizing algorithm to account for this correctly

Have you considered flexbox instead:

.grid {
  display: flex;
  flex-wrap: wrap;
}

.grid > div {
  flex: 1 0 200px;  /* can grow, can't shrink, minimum width 200px */
  max-width: 400px;
  margin: 5px;
}

.grid-item {
  width: 100%;
  height: auto;
}
<div class="grid">
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
  <div><img src="http://placehold.it/400x300" alt="" class="grid-item"></div>
</div>

revised codepen

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    Good idea, the broader browser support would be an added benefit. The last row is less than ideal, though. Can you think of an easy way to get the last items to have the same size as the other items, when they do not fill the full row? – Afterlame Aug 27 '17 at 09:32
  • Sizing flex items on the last row is a known problem. I've listed several solutions here: https://stackoverflow.com/q/42176419/3597276 – Michael Benjamin Aug 27 '17 at 11:59