Ali Jafarian

Today we’re going to build a responsive image grid using CSS. No fancy dancy JavaScript or frameworks needed, just good ‘ole HTML and CSS.

Image grids are used all over the web – for pictures, products, profiles… you name it! Why? Because they’re a great solution for displaying rows and columns of visual data. Now that we know why they’re useful, let’s dig in!

The HTML

Our HTML is a simple unordered list with the class of rig – <ul class=”rig”>. Inside each li we’ll throw in an image, an h3, and a p for some content. Note: these are all optional, you could easily create this grid with just images inside of the li‘s.

<ul class="rig">
	<li>
		<img src="images/pri_001.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_002.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_003.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_004.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
</ul>

The CSS

Now that we have our markup, we’ll add some styling to make our grid responsive. There’s a few critical things to understand here:

1) Display vs. Float

Normally, most web developers would float to get a “grid effect.” Instead, I’ve used the display: inline-block approach with a nice little hack – we set our ul to font-size: 0px and then our li‘s to font-size: 16px AND font-size: 1rem. What??? I know, it shocked me at first too, but it works! And the double font-size declaration is for our old friend IE (Internet Explorer doesn’t recognize rem units, so the 16px is a fall-back). I’ve added some extra li styling to make the grid look nice πŸ™‚

ul.rig {
	list-style: none;
	font-size: 0px;
}
ul.rig li {
	display: inline-block;
	padding: 10px;
	background: #fff;
	border: 1px solid #ddd;
	font-size: 16px;
	font-size: 1rem;
	vertical-align: top;
	box-shadow: 0 0 5px #ddd;
	box-sizing: border-box;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
}
ul.rig li img {
	max-width: 100%;
	height: auto;
	margin: 0 0 10px;
}
ul.rig li h3 {
	margin: 0 0 5px;
}
ul.rig li p {
	font-size: .9em;
	line-height: 1.5em;
	color: #999;
}

2) Math & Margins

The whole point of responsive [or fluid] grids is to do perfect math. For example, if we have 4 columns they should all equal 25% width. To create a grid with spacing (gutters) we need to also accommodate for margins. In this example, I’ve chose a universal margin of 2.5% for all grids. This translates into a left margin of 2.5% for each li and a negative left margin of 2.5% for the ul.

ul.rig {
	list-style: none;
	font-size: 0px;
	margin-left: -2.5%; /* should match li left margin */
}
ul.rig li {
	display: inline-block;
	padding: 10px;
	margin: 0 0 2.5% 2.5%;
	background: #fff;
	border: 1px solid #ddd;
	font-size: 16px;
	font-size: 1rem;
	vertical-align: top;
	box-shadow: 0 0 5px #ddd;
	box-sizing: border-box;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
}

Now we need a little math to figure out the li widths for each grid:

  • 2 Column Grid: 100% / 2 = 50%… 50% – 2.5% = 47.5%
  • 3 Column Grid: 100% / 3 = 33.33%… 33.33% – 2.5% = 30.83%
  • 2 Column Grid: 100% / 4 = 25%… 25% – 2.5% = 22.5%

Now that we have our li widths, we’ll create 3 separate classes for them. This way you can change the ul class to dictate how many columns you want.

/* class for 2 columns */
ul.rig.columns-2 li {
	width: 47.5%; /* this value + 2.5 should = 50% */
}
/* class for 3 columns */
ul.rig.columns-3 li {
	width: 30.83%; /* this value + 2.5 should = 33% */
}
/* class for 4 columns */
ul.rig.columns-4 li {
	width: 22.5%; /* this value + 2.5 should = 25% */
}

3) Media Queries

The icing on the cake is a few simple media queries. For this example, I’ve decided to turn the grid into one column at 480px wide (typical mobile breakpoint). To do so, I make all the li‘s 100% wide and remove their left margin. I also get rid of the negative margin on the ul. Feel free to experiment with different breakpoints if you want your columns to hit 100% width earlier (ex: 768px) or later (ex: 360px).

@media (max-width: 480px) {
	ul.grid-nav li {
		display: block;
		margin: 0 0 5px;
	}
	ul.grid-nav li a {
		display: block;
	}
	ul.rig {
		margin-left: 0;
	}
	ul.rig li {
		width: 100% !important; /* over-ride all li styles */
		margin: 0 0 20px;
	}
}

Finished Product

Your complete CSS should look like this:

ul.rig {
	list-style: none;
	font-size: 0px;
	margin-left: -2.5%; /* should match li left margin */
}
ul.rig li {
	display: inline-block;
	padding: 10px;
	margin: 0 0 2.5% 2.5%;
	background: #fff;
	border: 1px solid #ddd;
	font-size: 16px;
	font-size: 1rem;
	vertical-align: top;
	box-shadow: 0 0 5px #ddd;
	box-sizing: border-box;
	-moz-box-sizing: border-box;
	-webkit-box-sizing: border-box;
}
ul.rig li img {
	max-width: 100%;
	height: auto;
	margin: 0 0 10px;
}
ul.rig li h3 {
	margin: 0 0 5px;
}
ul.rig li p {
	font-size: .9em;
	line-height: 1.5em;
	color: #999;
}
/* class for 2 columns */
ul.rig.columns-2 li {
	width: 47.5%; /* this value + 2.5 should = 50% */
}
/* class for 3 columns */
ul.rig.columns-3 li {
	width: 30.83%; /* this value + 2.5 should = 33% */
}
/* class for 4 columns */
ul.rig.columns-4 li {
	width: 22.5%; /* this value + 2.5 should = 25% */
}

@media (max-width: 480px) {
	ul.grid-nav li {
		display: block;
		margin: 0 0 5px;
	}
	ul.grid-nav li a {
		display: block;
	}
	ul.rig {
		margin-left: 0;
	}
	ul.rig li {
		width: 100% !important; /* over-ride all li styles */
		margin: 0 0 20px;
	}
}

Finally, let’s add one of our .column- classes to our ul to specify how many columns we want the grid to be:

<ul class="rig columns-3">
	<li>
		<img src="images/pri_001.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_002.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_003.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_004.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_005.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
	<li>
		<img src="images/pri_006.jpg" />
		<h3>Image Title</h3>
		<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit...</p>
	</li>
</ul>

Summary

And that’s it! A simple, yet effective, responsive image grid using CSS. I hope this helps you in your projects. Feel free to chime in with questions and suggestions in the comments below.

Discussion

76 thoughts on “Responsive Image Grids Using CSS”
  1. If I try to style the text, the whole css doesn’t work anymore. How can I set the font that I want to use?

  2. Great tutorial. I want to ask.
    1.Why Without font-size: 0; it breaks and they don’t fit into one row(i have no idea what to write into google to find out about this hack- how it works)?
    2. It looks like margin-left: -2.5%; extends the wrapper to the left by 2.5%. In my code it only pushed it to the left;
    Please can someone explain these things in more detail?

    1. 1) The font-size: 0; is used to remove the default 4px right margin on inline-block elements. Google “display inline-block right margin” to learn more about this.

      2) We’re using a -2.5% left margin on the ul so that it accommodates for the 2.5% left margin on the li’s. In other words, if we didn’t have the -2.5% left margin our li’s would not fit on one row because their total width would be more than 100%.

      Hope that helps πŸ™‚

  3. Excellent tutorial indeed. I’m using 4 column layout and it works nicely in my laptop and it resizes nicely when I resize the browser but my only problem is when I access the page in my mobile phone it still shows 4 columns, it is not resizing to a single column automatically in my mobile phone. Is there any way I can correct it ? Thanks a lot.

    1. Hi Shanthi,

      In order for the li’s to fall into one single column you’ll need the media query code that switches them to 100% width at a certain breakpoint. I used 480px in this example, which you can see if you look at the last CSS that starts with @media (max-width: 480px). You’ll also need to make sure you’ve included the following meta tag in the of your page:

      Hope that helps!

  4. This is great! I’ve just tested it with WordPress in combination with Pods for WordPress and Pods Auto Frontier Template for WordPress and it works like a charm!
    This will help me make a great portfolio site. Thanks for sharing!

  5. Hi there,
    This has been really useful and easy to use. Is there any way to amend the css to account for viewing in IE8? In firefox/chrome the images appear in rows of 3 as I want but in Internet Explorer they just appear in a long list.

    Many thanks

  6. Hello, I have looked and can’t figure this out. I want to set the default to 4 columns without buttons, which line do i change. Thanks

  7. Hi, this is exactly what i was looking for….. i’m using wordpress with a child theme so i can make changes without problems.
    i create a site and paste the code in the content window, load the pictures, add the css but it shows me the image as a list, they don’t order in colums… do u actually know what it can cause this to happen?

    greetings

  8. Great tutorial! I got this to work and it looks awesome on my mobile phone.
    However, I tried to add some intermediate steps for other device breakpoints. For example I wanted to add a breakpoint to switch to two columns at 768 px for ipads, but couldn’t get it to work. I basically copied and pasted the media query section, but changed the max width to 768 and the width to 47.5%, but it still only switches from 3 columns straight to 1 column at 480 px. Any suggestions?

    1. For two column …..

      @media(max-width: 768px)
      {
      ul.grid-nav li {
      display: block;
      margin: 0 0 5px;
      }
      ul.grid-nav li a {
      display: block;
      }
      ul.rig {
      margin-left: 0;
      }
      ul.rig li {
      width: 45% !important; /* over-ride all li styles */

      }

      }

  9. Nice code.Helped a lot.I know it may sound like a dummy question,but in the grid how to align a picture to the center,as traditional methods dont seem to work.

    1. I had a similar problem. The problem was the margin/padding on the left side of the elements. To fix it, add this to the styles


      * {
      margin: 0;
      padding: 0;
      }

  10. Excellent work i appreciate but i am looking to display a new post in blogger in which thumbnail images should display containing link to that post these codes are not working in blogger as table is showing in bullets and it is not in grid style Here is Cartoon in HINDI

  11. hey great tutorial thanks a lot. I just have troubles with the gallery overlapping another section that follows (the orange that you see in the screenshot should be below the thumbnails from the gallery). What can I do to resolve this? I tried with and it doesn’t work

  12. How could one add an “enlarge on hover” to this code while maintaining the scaling to variable screen sizes?

  13. I’m very new at this and trying to add this to my wordpress site. Does the CSS need to go in a separate file or in the style.css?

  14. It sits offset to the right, and not centered, for me. I cannot figure out why it is doing it.

  15. I like this lots. Thank you for sharing it. I’d like to reproduce the same but with wider white spaces on the page, at left and right of the main body. That is, I’d like it being in a thinner wrapper or container. Is that an easy task for me as a beginner? How would I make your ‘body/container/wrapper’ (not sure of correct terminology) thinner please – what code would I write in the css file? This would be for the desktop size screen, as the smaller screens would of course be responsive to their smaller sizes, and their white space not so important to me. Thank you in advance.

  16. Thank you very much! this helped me so much with my project for an e-commerce website! πŸ™‚
    may i ask in what property of the style can i can resize the image grids? πŸ˜€

  17. Is there any plugin like jQuery Datatable that pulls data and then displays product catalog page by page in grid view and/or list view?

  18. This was great. My suggestion – use flexbox to get images of the same height, if your images are different heights or you have a different amount of paragraph text underneath each image.

    1. Hi Ilse,

      I’m glad the grid has been useful for you. Unfortunately, I don’t think mixing it with the CodeDrops filtering will be a trivial effort… as they are using some advanced CSS3 techniques for that kind of filtering. Helping you combine the two would be a tutorial in itself!

      I would advise that you either use theirs OR use some jQuery to filter my grid. In fact, I may whip up a tutorial on that soon… so stay tuned πŸ™‚

      Cheers,
      Ali

  19. Great article, thanks for the help! How would I go about making it fall to 2/3 columns (from the original 4 columns) on an iPad say for instance?

    Thanks, David

    1. Hey David,

      To accomplish this you would use media queries and change the width property of the . Below is some CSS that you can use that would make 3 columns in iPad landscape and then 2 columns in iPad portrait.

      /* —– iPad Landscape —– */
      @media (max-width: 1024px) {
      /* 3 columns */
      ul.rig li {
      width: 30.83% !important;
      }
      }

      /* —– iPad Portrait —– */
      @media (max-width: 768px) {
      /* 2 columns */
      ul.rig li {
      width: 47.5% !important;
      }
      }

      Note – we’re using !important to over-ride the CSS that takes place when changing column sizes (in the demo).

      Hope that’s helpful.

      Cheers,
      Ali

  20. Great tutorial. Exactly what I need. One challenge though, I want it set at 4 columns by default by I can’t seem to figure out how to. Please help with that. Thanks.

        1. Why don’t you make it a pop-up with slider?

          If you actually read the tutorial you wouldn’t have asked me that simple question about how to make it 4 columns. You obviously just copy/pasted and then posted a comment in here when you got stuck. That’s the PROBLEM with most people trying to learn web design… they don’t actually want to learn. They just want someone else to do the work for them. Your lucky I decided to help you.

          Do yourself a favor – READ tutorials so you can actually UNDERSTAND the code that you’re using.

          1. You’re right. My apologies. I though with my level of understanding, I should be able to figure it out. Thanks all the same. My unreserved apologies

  21. Ali great work!!! I’m using your tutorial as a template to build a Drupal 7 module. My paragraphs are of different sizes, which seems to make visually the heights on some of the grids different. Do you have any suggestions on how I should approach fixing them? Thanks

    1. Hey Bill – You have 2 options:

      1) You can play with heights and max-heights for your tags and then set overflow to hidden. This will basically truncate your paragraph text.

      2) You can use another grid solution called jQuery Masonry – http://masonry.desandro.com/. Masonry is designed to accommodate varying heights which gives you a masonry grid, instead of a perfect grid like this.

      This is no small task, either way. Good luck!

Leave a Comment

Your email address will not be published. Required fields are marked *