Photo of me! Eric Douglas Pratt

Intermediate: CSS Responsive Grids

  1. The HTML
  2. Getting Started
  3. Approach 1: Margins All Around
  4. Approach 2: Selective Margins via Nth-Child
  5. Approach 3: The Magic of Negative Margin

Thumbnail grids are a common feature of any website. There are many different ways to create them using CSS, but some are simpler and more cross-browser compatible than others. The task gets a little more complicated when the grids need to be responsive.

In this exercise, we'll walk through four different approaches to creating a responsive thumbnail grid that renders as one column on mobile, two columns on tablet, and three columns on desktop. Each approach will use essentially the same HTML.

Note: This exercise won't work in IE8, since it doesn't support media queries, and the JavaScript libraries we use to account for that don't work with the <style> tags we're using to insert our CSS into the page.

Follow along by making your own changes to this CodePen!

1. The HTML

Here's a collection of six thumbnails, each with an image and a description, wrapped inside a container.

<div class="thumbnails">
  <div class="thumbnail">
    <img src="thumb001.jpg" alt="Thumbnail" />
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.</p>
  </div>
  <div class="thumbnail">
    <img src="thumb002.jpg" alt="Thumbnail" />
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.</p>
  </div>
  <div class="thumbnail">
    <img src="thumb003.jpg" alt="Thumbnail" />
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.</p>
  </div>
  <div class="thumbnail">
    <img src="thumb004.jpg" alt="Thumbnail" />
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.</p>
  </div>
  <div class="thumbnail">
    <img src="thumb005.jpg" alt="Thumbnail" />
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.</p>
  </div>
  <div class="thumbnail">
    <img src="thumb006.jpg" alt="Thumbnail" />
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.</p>
  </div>
</div>

2. Getting Started

CSS floats make it easy enough to float each thumbnail to the left and give it a particular width. Media queries allow us to split the thumbnails into separate columns when the viewport gets wider.

.thumbnails .thumbnail img {
  width: 100%;
}

@media screen and (min-width: 480px) {
  .thumbnails .thumbnail {
    float: left;
    width: 50%;
  }
}

@media screen and (min-width: 768px) {
  .thumbnails .thumbnail {
    float: left;
    width: 33.333333%;
  }
}

I've added a header so we can see how well the thumbnails align with other page content. Here's what that HTML and CSS looks like so far:

Thumbnails
Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

That looks pretty good. Now we just need some margins so that the thumbnails aren't bumping up against each other. That's where the different approaches come in.

The first thing we'll want to do is change the box model on every element so that adding padding to an element doesn't increase its width. Getting into the different box models is a whole separate exercise, so for now, we'll just use the CSS below and trust that it will simplify our task greatly.

* {
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

3. Approach 1: Margins All Around

Since we're splitting up the thumbnails into columns based on percentages that add up to 100%, why don't we just specify the margins in percentages as well and subtract them from the thumbnail width, so that it still adds up to 100%?

.thumbnails .thumbnail img {
  width: 100%;
}

@media screen and (min-width: 480px) {
  .thumbnails .thumbnail {
    float: left;
    margin: 0 2% 2%;
    width: 46%;
  }
}

@media screen and (min-width: 768px) {
  .thumbnails .thumbnail {
    float: left;
    margin: 0 2% 2%;
    width: 29.333333%;
  }
}
Thumbnails
Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

This works, and is the approach taken by this tutorial, but as you can see, the left and right edges of the thumbnail gallery don't align with the header. You'd have to apply the same 2% margin to everything else on your page to get everything to line up.

4. Approach 2: Selective Margins via Nth-Child

Okay, so say we want the left edges of our thumbnails to align with the header. We can apply a margin to just the right side of each thumbnail, but then the right side won't align with the header. But what if we could turn off the margin just for the last thumbnail in each row?

How do you target every third element? You use the nth-child selector!

.thumbnails .thumbnail img {
  width: 100%;
}

@media screen and (min-width: 480px) {
  .thumbnails .thumbnail {
    float: left;
    margin: 0 2% 2% 0;
    width: 49%;
  }
  .thumbnails .thumbnail:nth-child(2n) {
    margin-right: 0;
  }
}

@media screen and (min-width: 768px) {
  .thumbnails .thumbnail,
  .thumbnails .thumbnail:nth-child(2n) {
    float: left;
    margin: 0 2% 2% 0;
    width: 32%;
  }
  .thumbnails .thumbnail:nth-child(3n) {
    margin-right: 0;
  }
}
Thumbnails
Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Perfect! The left and right edges of the thumbnail gallery line up with the header, and all our thumbnails are equally spaced.

The problem? The nth-child selector doesn't work in Internet Explorer, so this isn't a cross-browser solution unless you use a JavaScript library that runs through your CSS and forces it to work in IE, which is slow and less than ideal.

One way you can make this approach work in IE is to apply a particular CSS class to every second and every third element. That way you can target the last thumbnail in each row without using nth-child. But this is also less than ideal, especially when there's a better way in which you don't have to modify the HTML at all!

5. Approach 3: The Magic of Negative Margin

I credit the Starbucks Style Guide with introducing me to this approach. And it's so simple, I couldn't believe I hadn't thought of it before!

You set a negative left margin on the container so all its content moves to the left by that much. Then you set a positive left padding of the same amount on each thumbnail, and you're good to go! And you can even use the normal-sized percentages like 50% and 33.33333% without having to subtract anything to account for spacing.

.thumbnails .thumbnail img {
  width: 100%;
}

@media screen and (min-width: 480px) {
  .thumbnails {
    margin-left: -2%;
  }
  .thumbnails .thumbnail {
    float: left;
    padding-left: 2%;
    width: 50%;
  }
}

@media screen and (min-width: 768px) {
  .thumbnails .thumbnail {
    width: 33.33333%;
  }
}
Thumbnails
Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.

Thumbnail

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor fringilla fringilla. Sed rhoncus porta orci et dignissim. Praesent accumsan nisl ac velit tempus non elementum odio ornare. Vivamus iaculis suscipit venenatis. In eu risus orci, ac placerat felis. Suspendisse sed nunc eu ligula aliquam sagittis.