12

I'm trying to organize divs into two columns, but not force them into rows. I'm also trying to keep the vertical spacing between the divs a constant.

You can see the following demo, which would be correct if there wasn't huge amounts of vertical whitespace between the divs in each column.

html

<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>

I thought that I could just float them to the left with a static width, but apparently that didn't work.

Any ideas?

Community
  • 1
  • 1
qwerty
  • 5,166
  • 17
  • 56
  • 77
  • 2
    Can't be done with floats, only with absolute positioning or a jQuery plugin (like Masonry) – Andy Jan 11 '13 at 14:50
  • 1
    Yep, I was going to recommend Masonry also. – aardvarkk Jan 11 '13 at 14:50
  • 100%, that's not how floats work – Andy Jan 11 '13 at 14:50
  • Alright then, i'll take a look at it, it certainly looks interesting! – qwerty Jan 11 '13 at 14:53
  • @Andy - Based on his example, and assuming it's the desired goal, the OP is showing that floats do work that way (but maybe his question doesn't reflect his desired goal and floats don't work the way the question is asked). I think he's asking for an alternative to floats with static widths (ie CSS best practices) not for a way to accomplish with floats. But maybe I'm the one misreading... – Anthony Jan 11 '13 at 14:55
  • @Anthony The way I saw it was that he wants the div's to automatically move up into the white space on the demo. Unless he was to divide into two columns and treat them separately, the only way to achieve it would be to use masonry – Andy Jan 11 '13 at 14:56
  • This is using two columns: http://jsfiddle.net/89mW6/6/ And I don't think it is as he wanted – Andy Jan 11 '13 at 14:57
  • Sorry for being unclear. @Andy understood me correctly. – qwerty Jan 11 '13 at 15:00
  • @qwerty, I made a somewhat radical edit to your post in an attempt to make it clearer. Feel free to rollback the post if you think I messed up your message. – jamesplease Jan 11 '13 at 15:11
  • No that's pretty spot on, i was having trouble wording the question. Thanks for the clarification! – qwerty Jan 11 '13 at 15:48
  • 1
    Possible duplicate of [How to Create Grid/Tile View with CSS?](http://stackoverflow.com/questions/8470070/how-to-create-grid-tile-view-with-css) – Oriol Feb 12 '16 at 15:31

6 Answers6

21

Thanks to J.Albert Bowden for the fiddle

HTML

<div id="box">
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
    <div class="module"></div>
</div>

CSS

#box{
    -moz-column-count:3;
    -moz-column-gap: 3%;
    -moz-column-width: 30%;
    -webkit-column-count:3;
    -webkit-column-gap: 3%;
    -webkit-column-width: 30%;
    column-count: 3;
    column-gap: 3%;
    column-width: 30%;
}
.module{
    margin-bottom: 20px;
}
Vixed
  • 3,429
  • 5
  • 37
  • 68
  • Great concept. Except the question asks for two columns. – Michael Benjamin Feb 13 '16 at 20:59
  • Thanks @Michael_B It's just a method, not the solution. I'm still looking for a cross browser sol. That's why I started the bounty. – Vixed Feb 13 '16 at 21:04
  • I'm not sure it's a solution for this question, but a flex container in column-direction can be useful: http://jsfiddle.net/89mW6/74/ – Michael Benjamin Feb 13 '16 at 21:16
  • @Michael_B a column count solution will split the elements between columns if needed, a flex solution can not do that ... but on the other side, I don't see such requirement in the question – vals Feb 14 '16 at 21:31
  • @vals, yes. I understand. I mentioned flex columns for the sake of awareness. CSS columns (and grids) can certainly do things flex can't. – Michael Benjamin Feb 14 '16 at 21:38
  • @Michael_B it's simple enough to change it from 3 to 2 column [`column-count: 2;`](https://jsfiddle.net/7Chkz/1051/). – user692942 May 26 '16 at 13:14
8

First things first: you won’t be able to acheive a columnar wrapping layout with floats: as other commenters have pointed out, that’s just not how floats work. Nor is there an "automatic masonry-layout" module in CSS, which I suspect is what you’re really after. I also assume that placing each item individually is out of the question.

The closest thing you’ll get is Grid Layout—we’ll get to that towards the end. Spoiler: it’s really cool, but it’ll be a little while before browser support is really good.

So, TL;DR: there is no cross-browser method for doing a smart, row-by-row, masonry-like layout in CSS. But Grid Layout comes damn near. If you can't wait, use JS or switch the design to something that works with wrapping columns, for example.

If you choose the JS route, you could use the Grid Layout JS polyfill! That way, you can write grid layout syntax today, and remove the polyfill when it’s no longer needed, at some point in the future.


Columnar layout with multi-col

Judging from other answers and comments, a columnar wrapping layout is not what you want though. Just in case you still decide to go that route, you can do it with Multi Column layout. Support is pretty good: everything except IE<10, pretty much.

A quick example, just in case you want to change your layout to go in the multicol direction: here’s a JSBin with 2-column multicol layout. Note that you do not need to set both column-count and column-width: set a column-count (and column-gap) and the rest will sort itself out.

Oh, and if you get buggy rendering with margins (e.g. margins wrapping onto new columns, creating uneven layouts), the usual fix is to set display: inline-block; width: 100%; on the .module. Your milage may vary: for something that’s been around a long time, multicol sure is buggy.

Columnar layout with flexbox

Sticking with columnar layout for just a little bit longer, you can also use flexbox. (I see one other answer bringing up Flexbox, but sadly a completely outdated syntax which will not work in modern browsers).

The difference between wrapping into columns in multi-col vs flexbox is that flexbox does not balance the items into columns for you (it’s not really made for that type of layout), so you need to set a specific height in order to force the columns to wrap. If you have a container element (.container) and the .module items inside it, the following is the basic approach:

.container {
  display: flex;
  flex-flow: column wrap;
  height: 1000px; /* or whatever works for you */
}
.module {
  /* whatever props you want for modules */
}

...not counting prefixes and syntax variations for IE10, which uses a slightly older variation of the spec. (There’s also the old-old flexbox, which doesn’t support flex wrapping, so we’ll forget about that). Simple JSBin wrapping flexbox example here.

Dense packing with Grid Layout auto placement

Finally, we get to Grid Layout. This new spec has some really cool features, that allow us to do something close to a "Masonry" layout.

Heads up: you need to check these examples in Chrome Canary, WebKit Nightly or Firefox Developer edition. There is an old implementation of Grid Layout in IE10+ (and Edge as well), but it doesn’t contain all the new hotness properties we need.

First the markup: we’ll use a wrapper element + the .module items inside (the wrapper is not strictly necessary—we could have put the modules directly into body, but I just find it clearer this way):

<div class="container">
  <div class="module"></div>
  <div class="module"></div>
  <!-- and so on -->
</div>

Next, we tell the container to be a grid container:

.container {
  display: grid;
}

Then we set it to have a "template" for columns of 2 equal width columns (1 "fractional unit"), and gaps between columns as well as rows of 20px:

.container {
  display: grid;

  /* 2 columns, equally wide: */
  grid-template-columns: 1fr 1fr;

  /* gaps between each column and row. */
  grid-column-gap: 20px;
  grid-row-gap: 20px;
  /* ...can also be shortened to grid-gap: 20px; */
}

We have not yet given it a template for rows, but we only need to allow it to automatically create them as needed. For this, we set the grid-auto-rows property, to add as many 50px tall rows as needed:

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-column-gap: 20px;
  grid-row-gap: 20px;

  /* automatically create rows, 50px tall each: */
  grid-auto-rows: 50px;
}

At this point, we have not placed any items inside the container yet, at least not explicitly. With grid, you can specify exactly which area of the grid an item shoud belong in. The thing is, you don’t have to! The grid will place them automatically in the first available slot, starting at the top left and going row by row by default, unless you tell it otherwise.

Instead, we need to tell it that some items are bigger than others. We don’t use sizes for this, but instead tell odd items to span 2 rows, and every 3rd item to span 4 rows.

.module {
  background: yellow;
}

.module:nth-child(odd) {
  grid-row: span 2;
  background: green;
}
.module:nth-child(3n) {
  grid-row: span 4;
  background: orange;
}

Finally, we need to tell the grid to use the "dense" algorithm, meaning it will make one placement pass per item, trying to avoid making "holes" in the auto placement.

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-column-gap: 20px;
  grid-row-gap: 20px;
  grid-auto-rows: 50px;

  /* use the "dense" algorithm: */
  grid-auto-flow: row dense;
}

This gives us something very close to a "masonry" layout, as can be seen in this JSBin example of a dense grid layout — Again, note that you will need nightly/dev versions of Chrome/WebKit or Firefox to see how it works.

Here’s an image of the result, as viewed in Chrome Canary:

grid layout in Chrome Canary

Some things to note:

  • The row dense packing algorithm doesn’t really make a difference here, as the items happen to stack up in a pattern that leaves no holes, but I put it in there for completeness.
  • As you can see, there’s a lone item on the last row—grid can’t magically resize things (like a jQuery Masonry plugin, for example), it can only size according to grid positions or spans. It's not a silver bullet for box-packing algorithmic layout. That said, it’s incredibly powerful and fun once you master it. Within a year or so (at the max, my guess), it’ll be in all major (evergreen) browsers.
Emil
  • 1,949
  • 2
  • 16
  • 25
2

Try this.. http://jsfiddle.net/rymfev8c/1/

HTML

<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>

CSS

body {
  padding: 40px;
}

.module {
  height: 50px;
  width: 45%;
  margin-right: 3%;
 margin-bottom: 60px;
  background: yellow;
  float: left;
}

.module:nth-child(odd) {
  height: 100px;
  background: green;
 margin-bottom: 5px;
}
.module:nth-child(3n) {
  height: 200px;
  background: orange;
  margin-bottom: 5px;
}

omg its 3 years old..

Shashi
  • 33
  • 5
1

HTML

<div id = "box">
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
<div class="module"></div>
</div>

CSS:

#box{
display:box;
box-orient: vertical;
-webkit-display:box; 
-webkit-box-orient: vertical;
}

.module{
box-flex: 1;
-webkit-box-flex: 1;
}

This is box-flex, introduced in css3. you may have to use also -webkit-/ -moz- property, before "display", "box orient" and so on, it depends on the browser

Leo
  • 2,061
  • 4
  • 30
  • 58
  • 1
    could you provide a working fiddle? this style doesn't seem to obtain the OP desired layout (tried on Fx18, Chrome and Canary) – Fabrizio Calderan Jan 11 '13 at 15:26
  • Ooh, yes! I totally forgot about flexbox. I guess i could use it, but i would need some polyfills to make it cross-browser compatible, right? – qwerty Jan 11 '13 at 15:34
  • http://jsfiddle.net/UgWEH/, yes, you might want to use -moz- also, so it can work on firefox – Leo Jan 11 '13 at 15:35
  • I'm running it in Chrome 24 right now, and i'm just getting them in one row. Do i need Chrome Canary to see it? – qwerty Jan 11 '13 at 15:57
0

You can use table tag. Try something like this

HTML

<table cellpadding="0" cellspacing="0" width="100%" height="100%">  
  <tr>     
    <td>      
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>
    </td>
    <td>
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>
      <div class="module"></div>           
    </td>    
  </tr>  
</table>

CSS

body {
  padding: 40px;
}

.module {
  height: 50px;
  width: 45%;
  margin-right: 3%;
  margin-bottom: 20px;
  background: yellow;
}

DEMO: http://jsfiddle.net/89mW6/5/

Idrizi.A
  • 9,819
  • 11
  • 47
  • 88
  • I was thinking that the OP wanted them to be arranged in columns but not necessarily rows. Maybe I'm wrong, though! – jamesplease Jan 11 '13 at 14:58
  • That's not an option. If i were to use two seperate `` i might as well just create two seperate divs for each column; tables are meant for tabular data and it wouldn't make it easier to achieve the effect i want. The modules are laid out like the example code in the OP, that's all i've got to play with. I cannot change how the elements are printed out. – qwerty Jan 11 '13 at 14:58
0

I don't think this is a good practice but what i usually do in cases like this is building 2 div, set them side by side and just fill them up with whatever content you desire, but again, this is the way i do it, it might or might not work for you :)

pbrito
  • 84
  • 11
  • It's not a bad idea, but how I can do this in a **for each** statement? I mean suppose a **Select * from menu order by timestamp** how to put the firsts at the top? – Vixed Feb 19 '16 at 15:32
  • @Vixed mmmm never had to do that but if you assign an identifier to your divs such as a number that could iterate in a cycle, then select your content and populate the divs in the order you desire. Might require a bit of messing around with Javascript, for a quick answer, it's how i would do it – pbrito Feb 19 '16 at 15:49
  • To much stuff to do... and what about a responsive version? Take a look at my answer, is not cross browser, but for now Ill use it http://stackoverflow.com/a/35366720/1076753 – Vixed Feb 19 '16 at 15:52