ataddeini
ataddeini

Reputation: 4951

Expanding Vertical Space Issue with Floated Elements

I have a layout that requires a list of items to be organized into two vertical columns. The items are in a single list of <div>s, with the markup also being re-purposed for mobile, so I don't want to modify the structure.

The problem I have here is that each item has an expanding content area which the user can toggle, and when this content is expanded the vertical space for that column needs to expand downward with the other column staying fixed.

Right now I have a basic solution with floated items, but when I expand the content areas the vertical space expands in both columns instead of just the one.

Here's a link to an example of the functionality as I have it now, and below is a screenshot of what the desired behavior should be.

[screenshot]

Is it possible to style this to support the required behavior? Or am I going to have to modify the structure of items in order to get this to work? Thanks in advance for your help!

Upvotes: 5

Views: 391

Answers (6)

ScottS
ScottS

Reputation: 72261

Here's a PURE CSS SOLUTION for four panels (I don't know if you intended to have more, and I do not have six [2 wide 3 high] working yet--and suspect it is not possible). It works in FF and IE8/9. See the fiddle: http://jsfiddle.net/bEgwB/203/

However, IE8 experiences a redraw bug that keeps panel 3 from moving so it needs extra javascript help (added in fiddle above), and IE7 needs some margin adjustments to get panel 4 positioned correctly (but does not have the redraw issue even without the extra javascript help). UPDATE (11-18-11): here's the fiddle for IE7 margin adjustment: http://jsfiddle.net/bEgwB/286/

EDIT: a previous version of my CSS had display calls that were unnecessary.

HTML

<div id="container">
    <div class="panel one">
        Panel 1<br />
        <a class="more" href="#">more</a>
        <p>More Info 1 with some additional content</p>
    </div>
    <div class="panel two">
        Panel 2<br />
        <a class="more" href="#">more</a>
        <p>More Info 2 with some additional content</p>
    </div>
    <div class="panel three">
        Panel 3<br />
        <a class="more" href="#">more</a>
        <p>More Info 3 with some additional content</p>
    </div>
    <div class="panel four">
        Panel 4<br />
        <a class="more" href="#">more</a>
        <p>More Info 4 with some additional content</p>
    </div>
</div>

CSS

a {color:yellow;}
#container {width:0 ; padding: 0 130px;}
.panel {
    background-color:green;
    padding:5px;
    color:#fff;
    width:100px;
}
.panel p {display:none;}

.panel.one {
    float: left;
    margin:10px 0 10px -120px;
}
.panel.two {
    float: right;
    margin: 10px -120px 20px 0;
}
.panel.three {
    float: left;
    clear: left;
    margin:10px 10px 10px -120px;
}
.panel.four {
    clear: right;
    margin: 10px;
}

JAVASCRIPT

$('.more').click(function(e) {
    e.preventDefault();
    $(this).parent().children('p').toggle();
    /* the following fix IE8 */
    $(this).parent().parent().hide();
    $(this).parent().parent().show();
});

Upvotes: 2

sandeep
sandeep

Reputation: 92803

May be you can do it column-count property like this:

a {color:yellow;}
#container {
    width:300px;
    -moz-column-count: 2;
        -moz-column-gap: 50%;
        -webkit-column-count: 2;
        -webkit-column-gap: 50%;
        column-count: 2;
        column-gap: 50%;

}
.panel p {display:none;}
.panel {background-color:green;padding:5px;color:#fff;width:100px;margin:10px;}
.alt{
    margin-bottom:90px;
}

Check this fiddle http://jsfiddle.net/bEgwB/87/

UPDATED

Check this:

http://jsfiddle.net/bEgwB/276/

Upvotes: 1

Ilia Sachev
Ilia Sachev

Reputation: 76

If I correctly inderstand, that do you you want is something like this http://jsfiddle.net/bEgwB/275/

You need to use both css properties display:inline-block and float:left to implement effect like on your jpg. If my markup right and this looks as expected, I may help you with javascript, if it not ok now

Good luck.

Upvotes: 0

stslavik
stslavik

Reputation: 3028

Your premise is flawed. Document structure flows left-to-right, top-to-bottom. You will need to make some change to the structure... Easiest would be adding two containers for a left column and a right column. Otherwise, you're in for some tricky absolute positioning markup, and a little funky jquery, which I can only suggest with the addition of some unique IDs for each of the panels.

I would, personally, add ids such as panel1 through panel4 per your example, then use this javascript (or similar) as a jumping off point:

for(var i=1; i<=4; i++) {
        $('#panel'+i).css('left', function(index) {
           if(i%2 == 0) return "120px";
           else return "0px"; 
        });
}

$('.more').click(function(e) {
    e.preventDefault();
    $(this).parent().children('p').toggle();
    var id = $(this).parent().attr("id");
    switch( id ) {
        case 'panel1':
          console.log("panel1 found");
          $('#panel3').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        case 'panel2':
          $('#panel4').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        default: break;
    }
});

With the default values in the css for those panels:

#panel1 { top:0px; }
#panel2 { top:0px; }
#panel3 { top:56px; }
#panel4 { top:56px; }

The less you tweak the html, the more work you'll create in javascript.

edit:

Proposed alternate Javascript to remove need to alter HTML, assuming two elements per row. Since we know the row to be the problem...

var ct = 1
$('#container > div').each(function(index, domEle) {
  $(domEle).attr('id', 'panel'+ct);
  $('#panel'+ct).css({
     'position': 'absolute',
     'left' : function(index, value) {
        if(ct%2 == 0) return "120px";
        else return "0px"; 
     },
     'top' : function(index, value) {
        return (56 * Math.floor(ct/3)) + "px";
     }
  });
  ct++;
});

$('.more').click(function(e) {
    e.preventDefault();
    $(this).parent().children('p').toggle();
    var id = $(this).parent().attr("id");

    switch( id ) {
        case 'panel1':
          $('#panel3').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        case 'panel2':
          $('#panel4').css('top', function(index) {
            var buffer = $('#'+id).height() + 20 + "px";
            return buffer;
          });
          break;
        default: break;
    }
});

Now no changes need be made to the HTML, though you'll want to redo the click function to handle repositioning of elements after a click. I would make life easy and hide all .more items before expanding a new box, since it would mean having to calculate the heights of all elements above, but how much work you want to make is your business.

Upvotes: 3

COBOLdinosaur
COBOLdinosaur

Reputation: 294

There is a styling solution. To tie the two columns together they need an extra level of binding you can do that by adding a style attribute to "container", "display:table" and to the panels with "display:table-cell".

That will keep the heights in synch. Both "container" and the "panel" class must have a declared width or they really mess up the layout. IE is weak on support of these attributes, so that could be a problem with the solution.

Upvotes: 0

Pavel Podlipensky
Pavel Podlipensky

Reputation: 8269

You need to add two more div's - left and right column and split your items between these two divs. This is the way how to make them independent, here is jsfiddle for this.

HTML

<div id="container">
    <div class="left">
        <div class="panel">
            Panel 1<br />
            <a class="more" href="#">more</a>
            <p>More Info 1 with some additional content</p>
        </div>
        <div class="panel alt">
            Panel 2<br />
            <a class="more" href="#">more</a>
            <p>More Info 2 with some additional content</p>
        </div>
    </div>
    <div class="right">
        <div class="panel">
            Panel 3<br />
            <a class="more" href="#">more</a>
            <p>More Info 3 with some additional content</p>
        </div>
        <div class="panel alt">
            Panel 4<br />
            <a class="more" href="#">more</a>
            <p>More Info 4 with some additional content</p>
        </div>
    </div>
</div>

CSS

a {color:yellow;}
#container {width:300px; position:relative;}
.panel {background-color:green;padding:5px;color:#fff;width:100px;margin:10px;}
.panel p {display:none;}
.left {
    width: 50%;
    float: left;
}
.right {
    width: 50%;
    float: right;
}

Upvotes: 1

Related Questions