Image Grid With Consistent Sizes

This tweet by Nick Sherman and this article by Piper Haywood inspired me to work on an image grid with equally sized images. In previous articles I’ve explained how to make image grids like this:

There is one drawback to this approach: while all the available space gets used perfectly the size of images with equal ratios is different (this effect can be desired of course if one wants to put emphasis on certain photos). In the example above the first and last photo of the top row, the second photo of the middle row and the last photo of the bottom row all have the same aspect ratio for example, but they are all differently sized. Because their sizes get normalized for each row. Take a look at the ratio for each row and their sum:

1.500 + 0.667 + 1.500 = 3.667
1.300 + 1.500 + 1.000 = 3.800
0.667 + 1.000 + 1.500 = 3.167

By dividing the ratios of each row by their sum we get these percentages:

40.909% + 18.182% + 40.909% = 100.000%
34.211% + 39.474% + 26.312% = 100.000%
21.053% + 31.579% + 47.368% = 100.000%

And these percentages are used for their width. For all landscape photos we have three different widths: 40.909%, 39.474% and 47.368%.

Here is a grid of photos with normalized sizes and a 2% gap between them:

To achieve this I took the square root of each ratio. This way we get a normalized width value. An image with the ratio 1.5 has the width Math.sqrt(1.5) = 1.224 and height Math.sqrt(1.5) / 1.5 = 0.816 – multiplied this is 1.0.

Here are the square roots of each ratio in our example and their sum:

1.225 + 0.816 + 1.225 = 3.266
1.140 + 1.225 + 1.000 = 3.365
0.816 + 1.000 + 1.225 = 3.041

First we pick the row with the biggest sum (so all items are equally sized within the whole grid and not just their row): it’s the second one with the value 3.365. Then we divide each value by this and multiply by 0.96. As there’s a 2% gap we subtract this two times from the full width. The calculated percentages:

34.942% + 23.294% + 34.942% = 93.178%
32.528% + 34.942% + 28.530% = 96.000%
23.294% + 28.530% + 34.942% = 86.766%

What’s now different to the previous example: All photos with the same aspect ratio have the same width (for example all landscape ones 32.768%).

The HTML (for readability I’ve left out the images):

<div class="row">
  <div class="column" style="flex: 0 1 34.942%;">(…)</div>
  <div class="column" style="flex: 0 1 23.294%;">(…)</div>
  <div class="column" style="flex: 0 1 34.942%;">(…)</div>
</div>
<div class="row">
  <div class="column" style="flex: 0 1 32.528%;">(…)</div>
  <div class="column" style="flex: 0 1 34.942%;">(…)</div>
  <div class="column" style="flex: 0 1 28.530%;">(…)</div>
</div>
<div class="row">
  <div class="column" style="flex: 0 1 23.294%;">(…)</div>
  <div class="column" style="flex: 0 1 28.530%;">(…)</div>
  <div class="column" style="flex: 0 1 34.942%;">(…)</div>
</div>

The CSS:

.row {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

.row + .row {
  margin-top: 2%;
}

.column + .column {
  margin-left: 2%;
}

Between each row and each photo there is 2% gap. And all photos are centered (though taking other values for justify-content or align-items give interesting results).

And one last note: to keep things simple I’ve just took three items for each row. With a linear partitioning algorithm for example it would be possible to better distribute the items (but for this example the three items per row were anyway the best outcome).