Seamless Responsive Photo Grid

Published by Chris Coyier

Let's say you have a bunch of images you want to display, and the goal is to get them edge-to-edge on the browser window with no gaps. Just because you think that would be cool. They are of all different sizes. You don't care if they are resized, but they should maintain their aspect ratio. Like this:


Nice and seamless

Ideally we keep it pretty chill on the markup, like:

<section id="photos">
  <img src="images/cat-1.jpg" alt="Cute cat">
  <img src="images/cat-2.jpg" alt="Serious cat">
  ...
</section>

Without any CSS at all, the images will line up in a row since they are essentially inline-block:

Rivers of whitespace

But that's not quite what we want. Your mind might go right to some JavaScript solution. Possibly the super cool Masonry project. The problem with the JavaScript option is that it relies on the window.resize event which (to me at least) always makes pages feel sluggish (even if you are hip and do the unbouncing thing).

We can get this working the way we want it to with just CSS. What we need are vertical columns in which to place the images. That way the images will stack on top of each other, and the height issue is moot.

We could wrap equal numbers of images in floated divs, but that's not very easy to keep balanced. The trick is going to be to use Masonry CSS, where the vertical columns are made through the CSS3 property column-count. Yeah, literally, the thing where you can set text in narrow columns automatically.

So as long as the parent with the multiple columns is as wide as the browser window (default) and the column-gap is 0, we got it made in the shade. By setting the images width to 100%, they will take up exactly the width of one column.

Here's the CSS:

#photos {
  /* Prevent vertical gaps */
  line-height: 0;
   
  -webkit-column-count: 5;
  -webkit-column-gap:   0px;
  -moz-column-count:    5;
  -moz-column-gap:      0px;
  column-count:         5;
  column-gap:           0px;  
}

#photos img {
  /* Just in case there are inline attributes */
  width: 100% !important;
  height: auto !important;
}

But what about when the browser window starts getting narrow? 5 columns might be great for a very large browser window but too many for a smaller browser window (5 images side-by-side might get too narrow). We can fix the problem super easily by having media queries test the browser width and adjust the number of columns accordingly.

@media (max-width: 1200px) {
  #photos {
  -moz-column-count:    4;
  -webkit-column-count: 4;
  column-count:         4;
  }
}
@media (max-width: 1000px) {
  #photos {
  -moz-column-count:    3;
  -webkit-column-count: 3;
  column-count:         3;
  }
}
@media (max-width: 800px) {
  #photos {
  -moz-column-count:    2;
  -webkit-column-count: 2;
  column-count:         2;
  }
}
@media (max-width: 400px) {
  #photos {
  -moz-column-count:    1;
  -webkit-column-count: 1;
  column-count:         1;
  }
}

Fannnnnncy.

Demo

See the Pen Seamless Responsive Photo Grid by CSS-Tricks (@css-tricks) on CodePen.

What is cool about this technique to me is that since it's pure CSS, everything happens very smooth and fast. You can resize your browser all around and watch things resize and move very quickly.

What about, you know.

So as far as browser support, it's pretty good, except IE, where it only works in 10+. Otherwise: Firefox 3.6+, Opera 11.1+, Safari 4+, Chrome 10+. Might even be a bit deeper than that.

You might just skip a fallback, because whatever it's not that bad it just has some white gaps. Or you might use the Modernizr/YepNope combo (Modernizr can test for it as csscolumns) to load up jQuery Masonry and see what you can do with that. Or you could test for it and roll your own JS which counts the images and splits them up into equal groups and wraps floated divs around them. Whatever floats your boat.

Super cute cats!!

Totally. They are from LoremPixel. For the demo we grabbed photos in random sizes with jQuery:

function getRandomSize(min, max) {
  return Math.round(Math.random() * (max - min) + min);
}

for (var i = 0; i < 25; i++) {
  var width = getRandomSize(200, 400);
  var height =  getRandomSize(200, 400);
  $('#photos').append('<img src="//www.lorempixel.com/'+width+'/'+height+'/cats" alt="pretty kitty">');
}