28

Given 9 divs one after another, I want to create a grid 3X3 via CSS.

How do I do that?

.cell {
  height: 50px;
  width: 50px;
  background-color: #999;
  display: inline-block;
}

.cell:nth-child(3n) {
  background-color: #F00;
  /* what property should I use to get a line break after this element? */
}

/* this doesn't work; at least not in safari */
.cell:nth-child(3n)::after {
  display: block;
}
<div class="grid">
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
</div>

Note: I don't want float/clear solution. Focus is on CSS and not HTML restructure.

If I add content: '\A'; white-space: pre; to ::after output comes out to be ugly.

.cell {
  height: 50px;
  width: 50px;
  background-color: #999;
  display: inline-block;
}

.cell:nth-child(3n) {
  background-color: #F00;
  /* what property should I use to get a line break after this element? */
}

.cell:nth-child(3n)::after {
  display: inline;
  content: '\A';
  white-space: pre;
}
<div class="grid">
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
</div>

How do I go about getting all div in a 3X3 row-column layout?

dippas
  • 58,591
  • 15
  • 114
  • 126
  • Related: [Responsive CSS Grid with persistent aspect ratio](https://stackoverflow.com/q/51577807/104380) – vsync Oct 27 '20 at 12:48

5 Answers5

40

02/2022 Update: As David mentioned in the comments, grid-gap is now deprecated and was replaced with the tidier gap. I've updated the code snippet below to reflect this.


Now that CSS Grid is fairly very well supported, I thought I'd supplement the others answers with a more modern solution.

.grid {
  display: grid;
  gap: 1px;
  grid-template-columns: repeat(3, 1fr);
}

div > div {
  padding: 10px;
  background-color: #ccc;
}
<div class="grid">
  <div>item</div>
  <div>item</div>
  <div>item</div>
  <div>item</div>
  <div>item</div>
  <div>item</div>
  <div>item</div>
  <div>item</div>
  <div>item</div>  
</div>
Andy Hoffman
  • 18,436
  • 4
  • 42
  • 61
27

This layout is simple with CSS flexbox. No changes to HTML.

.grid {
  display: flex;                       /* establish flex container */
  flex-wrap: wrap;                     /* enable flex items to wrap */
  justify-content: space-around;
  
}
.cell {
  flex: 0 0 32%;                       /* don't grow, don't shrink, width */
  height: 50px;
  margin-bottom: 5px;
  background-color: #999;
}
.cell:nth-child(3n) {
  background-color: #F00;
}
<div class="grid">
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
</div>

Benefits of flexbox:

  1. minimal code; very efficient
  2. centering, both vertically and horizontally, is simple and easy
  3. equal height columns are simple and easy
  4. multiple options for aligning flex elements
  5. it's responsive
  6. unlike floats and tables, which offer limited layout capacity because they were never intended for building layouts, flexbox is a modern (CSS3) technique with a broad range of options.

To learn more about flexbox visit:


Browser support:

Flexbox is supported by all major browsers, except IE < 10. Some recent browser versions, such as Safari 8 and IE10, require vendor prefixes. For a quick way to add prefixes use Autoprefixer. More details in this answer.

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Hi Anubhav - Thanks for the edit. I rolled it back only because it didn't work. If you want a pixel width for each cell, you need to specify a width on the container. Otherwise, they won't wrap unless the screen is very narrow. That's why I used percentages for the demo. What's the width of the container? – Michael Benjamin May 28 '16 at 18:51
  • A. What do you mean it didn't work? B. I am not fixing `width`, I am setting upper limit to it. C. It wrapped on my 2000px wide monitor just fine. D. Did you even run the code? –  May 28 '16 at 18:59
  • I did run it. It showed a single row of items all the way through. That's why I rolled back the edit. – Michael Benjamin May 28 '16 at 19:00
  • What browser are you using? version, os etc.? –  May 28 '16 at 19:04
  • Tested on current Chrome and FF. As I said in my first comment, they will wrap eventually, when the screen is narrow. On wider screen it's a single row. But if that's what you want, you're all set. – Michael Benjamin May 28 '16 at 19:06
  • 1
    Okay. Just beware of browser compatibility. Here's [**Chrome**](http://imgur.com/9mfq73p) and [**Firefox**](http://imgur.com/PWN3bEo). – Michael Benjamin May 28 '16 at 19:10
  • 1
    Also note that `calc` will not work with `flex-basis` component of `flex` shorthand property on IE11. You'll need to use `flex-basis` directly. – Michael Benjamin May 28 '16 at 19:14
  • 1
    Good answer. As a side note, given the problems with the calc expression, and also for personal tastes, I would remove the horizontal margin and just set the flex-basis to say 30%. Given the proper justify-content, the separation between items will be responsive. – vals May 29 '16 at 08:11
7

Besides Excellent answer from @Michael_B to use flexbox, you can use

  • CSS tables

    or

  • float:left

    both to support old browsers such as IE 8/9 , which flexbox won't support.

Note IE8 won't support nth-child but supports first/last-child

Option1 (CSS Tables) : with changes to HTML, wrapping each 3 cells in a row.

.grid {
  display: table;
  border-spacing: 5px
}
.row {
  display: table-row
}
.cell {
  width: 50px;
  height: 50px;
  background: grey;
  display: table-cell;
}
.row div:last-child {
  background: red
}
<div class="grid">
  <div class="row">
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
  <div class="row">
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
  <div class="row">
    <div class="cell"></div>
    <div class="cell"></div>
    <div class="cell"></div>
  </div>
</div>

Update

Option2 (float:left): with NO changes to HTML, using clear:left at each (4th)n item.

.cell {
  width: 50px;
  height: 50px;
  background: grey;
  float: left;
  margin: 5px
}
.cell:first-child + div+ div,
.cell:first-child + div+ div + div + div + div,
.cell:first-child + div+ div + div + div + div + div + div + div {
  background: red
}
.cell:first-child + div+ div + div,
.cell:first-child + div+ div + div + div + div + div,
.cell:first-child + div+ div + div + div + div + div + div + div + div {
  clear: left
}
<div class="grid">
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
  <div class="cell"></div>
</div>
dippas
  • 58,591
  • 15
  • 114
  • 126
  • Erm, I think IE 8 won't support `flexbox`. IE 9 does, partially. Crashes on `background` or some related property. –  May 28 '16 at 19:09
  • 1
    IE9 doesn't support at all, you can see here http://caniuse.com/#feat=flexbox, I just gave you another solution :) – dippas May 28 '16 at 19:11
  • Sorry my mistake. In my mind I was thinking about `calc`. –  May 28 '16 at 19:22
  • 1
    No problem ;), As I said just gave you a cross-browser solution. – dippas May 28 '16 at 19:24
  • This uses HTML restructuring. –  May 28 '16 at 19:25
  • @AnubhavSaini it is been a long time, but I've updated the answer with an option, if you want to take a look – dippas Jun 10 '16 at 22:58
3

Just to add another, you can also make a 3x3 grid using only a single <div>. Plunker

HTML:

<div class="grid"></div>

CSS:

.grid {
  width: 50px; height: 50px;
  background-color: red;
  border-top: 50px solid red;
  border-bottom: 50px solid red;
  margin: 0 50px;
  position: relative;
  box-shadow: inset 0 4px 0 -2px white,
              inset 0 -4px 0 -2px white;
}
.grid::before {
  content: '';
  width: 50px; height: 50px;
  background-color: red;
  border-top: 50px solid red;
  border-bottom: 50px solid red;
  margin: 0;
  position: absolute; left: -52px; top: -50px;
  box-shadow: inset 0 4px 0 -2px white,
              inset 0 -4px 0 -2px white;
}
.grid::after {
  content: '';
  width: 50px; height: 50px;
  background-color: red;
  border-top: 50px solid red;
  border-bottom: 50px solid red;
  margin: 0;
  position: absolute; right: -52px; top: -50px;
  box-shadow: inset 0 4px 0 -2px white,
              inset 0 -4px 0 -2px white;
}
C14L
  • 12,153
  • 4
  • 39
  • 52
0

I know the question is asking for a non-float clear solution, but after trying the flexbox solution I found that it did not preserve the width of my elements (further reading suggests I may have needed to set the width on the container element). In the specific case of a 3x3 grid however (as opposed to a grid with n rows of three) that a float clear solution more concise and works nicely. Here it is in case others find this answer when looking for a solution as I did:

.cell {
  float: left;
  height: 100px;
  width: 100px;
  margin: 5px;
}
.cell:nth-child(4) {
  clear: left;
}
.cell:nth-child(7) {
  clear: left;
}
Bjornicus
  • 1,087
  • 1
  • 8
  • 14