Forum Moderators: not2easy

Message Too Old, No Replies

Two column "liquid" layout

How can I make a two-column "liquid" layout in CSS without using tables?

         

Henrik001

9:45 am on Aug 4, 2005 (gmt 0)

10+ Year Member



How can I make a two-column "liquid" layout in CSS without using tables?

I thought this was as simple as floating two divs and give them each a width of 50%. This works great until I add, say a 1px border to the divs. Then column 2 is placed below column 1, instead of being placed to the right of column 1. I guess this happens because with the border added the total width of the div is 50% + 1px, which is more than 50% and causes the div to be moved below.

So how can I setup a 50%-50% column layout and don't worry about borders, margins and paddings messing up the layout?

It could probably be done with some javascript calculating the pixel-width to use instead of the percentage-width, but I dont't want to use javascript for layout.

Moving from table-based design into pure CSS I seem to encounter endless problems when trying to make even the most simple layouts. In this case it's so tempting just to make a 100% table, add to 50% td's and put the divs in those. But there must be a way to do this in CSS without falling back to tables?

zackattack

10:07 am on Aug 4, 2005 (gmt 0)

10+ Year Member



Hi Henrik001, welcome to WebmasterWorld...

I was recommended to keep clear of floated layouts until I got a really thorough grasp of layout in CSS. If you are new to layout I would recommend the same, unless you have oodles of time to fiddle and plenty of hair left to pull out.

You can acheive liquid 2column with positioning the right hand coloumn, something like:

HTML:

<div ="leftWrap"><p>Stuff in here.....</p></div>
<div ="rightWrap"><p>Stuff in here.....</p></div>

CSS:

#leftWrap {
margin-right: 50%;
}
#rightWrap {
position: absolute;
top: 0;
right: 0;
width: 50%;
}

You could then place another set of divs inside these for the content and add padding (should bypass ie 5's box model problem then too) somthing like:

HTML:

<div id="leftWrap"><div id="leftContent"><p>Stuff in here..</p></div></div>
<div id="rightWrap"><div id="leftContent"><p>Stuff in here..</p></div></div>

CSS:

#leftWrap {
margin-right: 50%;
}
#rightWrap {
position: absolute;
top: 0;
right: 0;
width: 50%;
}

#leftContent {
padding: 10px;
}
#rightContent {
padding: 10px;
}

This is one of several ways of doing it... also check out:

[css-discuss.incutio.com...]

Hope this helps

ZAttack

BeeDeeDubbleU

10:09 am on Aug 4, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



Google it and you will get more answers than you can shake a stick at :o)

createErrorMsg

10:49 am on Aug 4, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



I guess this happens because with the border added the total width of the div is 50% + 1px, which is more than 50% and causes the div to be moved below.

You've got it exactly right. It's called float wrapping.

So how can I setup a 50%-50% column layout and don't worry about borders, margins and paddings messing up the layout?

There are two ways to avoid this situation. One is to adjust the widths of your divs to allow room for the 1px border. Since there's no way to tell the browser you want the width to be 50%-1px, you would have to try sizing the diva at 49%. Since 1px on eahc side of the div is unlikely to total 1% of the browser screen, this should work without breaking your layout. However, you lose the precision in this way.

The second, and better, approach, is to avoid the problem altogether by never putting a width and a border and/or padding on the same element. In this case, that means you can't put a border on the widthed div, but there's nothing that says you can't nest a div inside of that div, and put the border on that...

html:
<div id="left_outer">
<div id="left_inner">
<p>Lorem ipsum dolor sit amet.</p>
</div>
</div>
<div id="right_outer">
<div id="right_inner">
<p>Lorem ipsum dolor sit amet.</p>
</div>
</div>

css:
#left_outer, #right_outer{width:50%; float left;}
#left_inner, #right_inner{border:1px solid #000;}

Because divs are block level elements, they automatically fill their containers, so when the inner divs are rendered, the browser will first place the border, then use the rest of the available space in side of the outer div for the width of the inner div. Result? A 50% wide box with a 1px border inside.

cEM

Henrik001

6:33 pm on Aug 4, 2005 (gmt 0)

10+ Year Member



Thanks for your replies. Both will do nicely, but I'll think I'll stick to the nested div solution.

Thanks.

However, it seems to me that it takes a bit more twisting and wrestling to get thinks to behave the way I want with CSS.

If I could hand-write every page of HTML it would probably not be a big deal to apply those "hacks" here and there, but when building flexible page templates to use in CMS, CSS seems more fragile than good old robust tables. But hey, who said it should be easy to replace table layouts with CSS ;-)

One last note:
What I really like about ditching table-based layouts, is the opportunity to write semantically nice HTML. But by inserting wrapper-divs, or other HTML elements only to be used for CSS layout, don't you think we yet again begin to move away from semantical correct HTML..?

Anyway, I sure prefer a few extra divs rather tnat a few extra tables ;-)

createErrorMsg

9:21 pm on Aug 4, 2005 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



But by inserting wrapper-divs, or other HTML elements only to be used for CSS layout, don't you think we yet again begin to move away from semantical correct HTML..?

Although I see where the argument comes from, I happen to disagree with the notion that adding an additional wrapper div or two is more semantically invalid. Remeber that technically, semantic means "of or related to meaning." So putting headers in <hx> tags and paragraphs of text in <p> tags is semantic because the tag conveys something about the meaning and context of what's in it.

But a div, even just one div, has no semantic meaning at all. A div is simply a generic, block level element. It establishes no meaning-based context within the document. It's just a box. It tells the browser nothing about the stuff contained inside of it.

To say it's un-semantic to use an extra wrapper div is to ignore the fact that using even ONE wrapper div is un-semantic. Yet a page styled ONLY with semantic elements would be severely limited in it's styleability. I think not even the most staunch of code purists would go there. ;)

That said, the only reason a nested div is required in this situation is because you're using a percent width and a pixel border. The two units don't mix well, so you have to seperate them. I suggested that approach because your original post mentioned two floated divs, but that's not necessarily CSS's best solution for a fluid two column layout, especially when you need borders applied.

Another approach would be to float only one div, leave the other in flow and give it a margin on the float side equal to the float's width. Then the border goes on the container of the two columns, with one in the middle to seperate the two. Here's a test page...

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd"><html>
<head>
<title></title>
<style type="text/css">
*{
margin:0;
padding:0;
}
#container{
border:1px solid #000;
}
#left{
float:left;
width:50%;
}
#right{
margin-left:50%;
border-left:1px solid #000;
}
</style>
</head>
<body>
<div id="container">
<div id="left">
<p>left</p>
</div>
<div id="right">
<p>right</p>
</div>
</div>
</body>
</html>

You may have to apply a faux columsn technique to mimic the extension of the middle border when the left column is longer than the right, but this gives the general idea.

To me this is the real beauty of CSS: there are so many options, so much flexibility, that you can almost always find a way to accomplish what you want, within the parameters that you need. It's just a question dropping back when you hit a wall to see what other options you have. That's not to say you'll always find the perfect answer, but 9 times out of 10 you'll be able to get really close.

cEM