Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stacking divs with variable height in 2 columns like Facebook Timeline

Tags:

html

css

I want to create a natural flow of content. The problem that I now face is that the <div>s will only line up next to each other. They will not pass the bottom edge of the floated block on the opposite side.

The following illustration clearly shows the problem. Let's say that I have 4 <div>s with variable heights:

  • Div1 always starts left
  • Div2 always is displayed on the right side
  • Div3 is on the left or right side, depending on the hight of Div1 and Div2
  • Div4 in this situation, Div4 doesn't stick to Div2's bottom
  • Div5 the same problem occurs

So, the position of the divs > Div2 should be determined by the height of the previous divs. Could you please advise me on how to achieve this?

enter image description here

like image 597
Wouter Dorgelo Avatar asked Feb 04 '12 14:02

Wouter Dorgelo


2 Answers

After checking the Facebook CSS and HTML, I found they achieve this using a list and alternating the float on the li elements between left and right (ie, every even element is floated right)

For example:

HTML

<ul>
    <li>...</li>
    <li>...</li>
    <li>...</li>
</ul>

CSS

li {
    clear: left;
    float: left;
    display: block;
    height: 100px;
    width: 200px;
    margin-bottom: 10px;
}

li:nth-child(2n) {
    clear: right;
    float: right;
}

Working example: http://jsfiddle.net/gBVPj/

This approach only works if an element on one side does not exceed the height of two elements on the other side. For example, in your diagram, should box 2 have a height larger than that of box 1 and 3 combined, then box 5 will be displaced and positioned inline with box 4.

Like this: http://jsfiddle.net/gBVPj/1/

I have not found an example of this problem on Facebook (one element never exceeds the height of two) so I believe that they have taken this into account. They could possibly be achieving this by using JavaScript - if you check the elements, they have a property data-height which matches the height of the element.

like image 187
My Head Hurts Avatar answered Oct 18 '22 19:10

My Head Hurts


I worked on this last night and found a rather simple way to do.

Compare the bottom position of the left column and the right column, append the new li element to the side with smaller value, which can be done by th e following way:

var last_left_post = $('.left:last');
var last_right_post = $('.right:last');
var left_position = 0;
var right_position = 0;

left_position = last_left_post.height() + last_left_post.offset().top;
right_position = last_right_post.height() + last_right_post.offset().top;

if(left_position<=right_position){
    $('#timeline').append('<li class="left"></li>');
}else{
    $('#timeline').append('<li class="right"></li>');
}

.left and .right using the same css as you do.

like image 29
Junyuan Avatar answered Oct 18 '22 19:10

Junyuan