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.


  • John

    Awesome! Thanks for sharing.

  • Carmen

    Excellent image grid! Thank you :)

  • Robin

    Nicely written, clean code and it works perfectly ! Thanks ! :)

  • AnoyMous

    nice share ;)

  • Jacob

    This is very helpful 5 stars!!

  • Thankan Muvattupuzha

    How can separate this without button? I need only 3 colum how can this?

    • Don’t include the buttons then. Just put one in your page and you should be good to go.

      • Mary

        The 4 column grid doesn’t work on safari. It only shows 3 columns. Any fix for this?

  • Alex

    Thank you! finally got a grid sorted out with your help! Yaaaaaaaaaaayyy!

  • lola123

    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?

    • You’ll need to do your styling on the or it’s child elements. For example, if you have an inside the you could assign it font-family, font-size, etc.

  • Alex

    Great tutorial. Just wondering why I don’t get a margin of 2.5 on the right side??

  • Tomas Habrman

    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) 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 :)

  • Shanthi

    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.

    • 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!

      • Shanthi

        Thanks a lot indeed ! made it work perfect !

  • 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!

  • James

    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

    • Nouvice

      I want to arrange clickable images in a thumbnail, kindly asist me with the code of possible.

  • Mike

    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

  • Amit

    Hey …how i can include this in php …So that all my product from database visible in grid

  • Alva

    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

    • alva

      nevermind it works now, thank you for this tutorial !!1

  • Midori Patterson

    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?

    • Manish Puri

      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 */

      }

      }

  • tarkan

    Very nice, very simple and gets the work done, thanks for sharing :) !

  • Jimmy Laroche

    Thanks a lot for this tutorial :)

  • shiv kumar

    Nice that’s really an useful article …… thank you for it

  • habeeb sule

    great code it helped me a lot

  • Anon

    Thank you!!

  • FaithTheLegend

    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.

    • FaithTheLegend

      Nevermind,seems like adding an align to the attribute works just fine.

  • DonDroga

    I wonder why mine isn’t centered on page like yours?

    • Ethan

      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;
      }

  • developer

    not working properly in safari…

  • Fabiha

    How would I load in images from php database?

    • Huz Gala

      You could add a column in the database which holds the urls to the images.

  • Shakeel Younis

    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

  • C Patel

    how can i get this layout to play nicely with bootstrap?

  • Huz Gala

    Excellent! How do I edit the properties of the boxes though? such as the height and the width

  • Sid

    very useful…thank you. All the best.

  • Sebastian Angelo-Perez

    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

  • Tom Woodward

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

  • Scott

    Beautiful, clean work, Thanks!

  • Kathleen

    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?

    • Hi Kathleen,

      All you need to do is add the CSS to your style.css. Then put the HTML in your post or page template.

      • Kathleen

        Thank you so much! That worked!

  • Jason Daniel

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

  • Lisa

    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.

  • Jaeson Pangilinan

    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? :D

  • flaxicom.com

    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?

  • Pavan.Maganti

    Thanks for Sharing..

  • Thanks man, works perfecly!

  • This is a photo gallery that is very exelence and it works well. We thank you very much to alijafarian.com on this tutorial. you can see the tutorial in working view click on these links http://lp3.web.id/pages/gallery

  • Channeling: Fred…

    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.

  • ADilet Zholdoshbekov

    Thank you!

  • Ilse Mul

    Hi,
    I’ve used this script for a while already on my portfolio site. I really like it.
    I was wondering, though,how I can make it filterable as well, like here: http://tympanus.net/codrops/2012/01/09/filter-functionality-with-css3/
    The combination of the two is exactly what I’m looking for, but I haven’t found it yet.

    Thanks for the help!

    • 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

  • Moch Lutfi

    work perfectly. thanks for sharing. :D

  • David Champion

    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

    • 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

      • David Champion

        You wonderful human being you. Many, many thanks *panic over* :-)

  • Pingback: Pure CSS Fluid responsive grid with content filter - Technology()

  • Clip Hut

    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.

    • Set the unordered list to – .

      • Clip Hut

        Perfect! You’re great.
        Wondering why you didn’t make it a pop-up with slider though.

        • 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.

          • Clip Hut

            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

          • Clip Hut

            I still won’t have understood it. I just read it over and again. Thanks for explaining

  • Bill King

    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

    • 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!

      • Bill King

        Thank you!!!

  • Rija Hafizie

    … I like it, Thanks for sharing