Flexible equal height columns
Creating a decent layout system using div-elements and css has been a pain in the excretory organs for web developers worldwide. As a matter of fact, we (that includes mister Onderhond) have never come across a solution that works for every single situation. In our little agile world, this means only one thing: to the drawing tables!
The requirements
As we're trying to build a solid layout system, we have a few basic requirements to fulfill.
- Table-less layout
- Valid and semantic markup
- Equal height columns
- Cross-browser compatibility
- Combine fixed and liquid columns
- Support elastic design
Now, we know that these requirements have been fulfilled by several other (and well known) layout systems like Faux absolute positioning, the Holy Grail and the (more recent) Absolute Columns. No offense to the people who came up with these techniques (you were a real source of inspiration), but as we see it, none of them are completely usable in each and every situation, thus not offering the flexibility we are looking for here.
Apparently, our list of requirements is not yet complete. We need to add a few extra items:
- Source-order independent
- backgrounds and borders definable by css
- (Re)Usable in almost all situations
We have been looking into this a lot, and here we are presenting a solution that suits our needs. Even though we will have to sacrifice a little bit of semantics (a wrapper where needed), we fulfill every other requirement with grace. As usual, IE proves to be the biggest bully of the gang, but we manage to tame it using just a minimal amount of scourging. Optimal flexibility is the main goal here, so the semantic sacrifice is gladly made.
The HTML
Without further ado, here is the markup that we will use for our flexible solution.
We can imagine a lot of developers frowning their eyebrows and raising their fists in rebellion to the amount of div's presented here, but as said, we need flexibility. First of all, the outer div (gridTwoLeft) will be used to define the position of our columns. As you can probably guess, changing the class into gridTwoRight will swap their position. Furthermore, we will use this class to define the background for one of the columns. The background for the other column will be defined on the wrapper-div. This wrapper-div will also serve as a means to draw a border between both columns by using just the css border property. Note that we add the infamous clearfix to the wrapper div because we will be floating the elements inside.
Next up, our two columns. Both these classes (col1 and col2) will only be used for positioning, not for any further styling. With all css in place, this should be sufficient to have the layout system we want to achieve. Nonetheless, we would like to add two more div elements to have an easy way to control the padding inside both columns. We could off course use the elements inside the columns to provide the padding, but this would decrease both flexibility and re-usability.
The CSS
Let's take a look at the CSS code.
.gridTwoLeft {background:#666666; padding-left:12em;}
.gridTwoLeft .wrapper {background:#EEEEEE;}
.gridTwoLeft .wrapper .col1 {width:100%; float:right;}
.gridTwoLeft .wrapper .col2 {margin-left:-12em; width:12em; float:right;}
.gridTwoLeft .wrapper .col1 .paddingBox {padding:1.5em 2em;}
.gridTwoLeft .wrapper .col2 .paddingBox {padding:1.5em 2em;}
This is where the magic happens. As you could see in the markup, both columns are structurally inside the wrapper div, thus giving the wrapper div the height of the biggest column. The result: our layout grid will expand vertically to match the height of the higher of both columns. What happens next is that our outer div (the gridTwoLeft) is provided with a left padding to create some space for the second column. Using a negative margin, we will then position this second column outside of the wrapper div, into the newly created (padded) space.
Due to the fact that no width is declared on the wrappers and that one of the columns is given a 100% width, the layout will scale depending on the width of the surrounding container. The following visual representation will most definitely clarify a lot.
Using the float property in combination with the negative margin allows us to put the col2-div in place. Note that we left out the two extra divs that are used to provide padding as they are not crucial for the layout system to work. The image above also clearly shows that the wrapper-div can be used to add a left border, visually separating our two columns.
Scourging IE6 for bad behavior
Due to IE6 having some strange behavior (like the double margin bug) towards floated elements and negative margins we need to add a few lines of code in our IE6 style sheet which we will, as alwasy, include using conditional comments.
.gridTwoLeft .wrapper .col1 {display:inline;}
.gridTwoLeft .wrapper .col2 {position:relative; display:inline;}
Expanding for flexibility
As mentioned earlier, we could like to be able to swap the position of our columns by changing the class on the outer div. To achieve this, we need to define the gridTwoRight the same way we defined the gridTwoLeft. We'll show you:
.gridTwoRight {background:#666666; padding-right:12em;}
.gridTwoRight .wrapper {background:#EEEEEE;}
.gridTwoRight .wrapper .col1 {width:100%; float:left;}
.gridTwoRight .wrapper .col2 {margin-right:-12em; width:12em; float:left;}
.gridTwoRight .wrapper .col1 .paddingBox {padding:1.5em 2em;}
.gridTwoRight .wrapper .col2 .paddingBox {padding:1.5em 2em;}
The idea here is that you can re-use these blocks of css code as a component within various contexts. Preceding the selectors with another class or an id (depending on the context), gives you the basic layout as it has been defined earlier, but allows you to overrule certain values like the width of the columns. Watch out when defining a gridTwoLeft within a gridTwoRight, as you will want to neutralize some styling-rules that are applied through the cascade.
The result
To round it all up: our example page.
Feel free to experiment with different column widths like a gridTwoEven at 50% etc. Should you run into trouble, use the comment form below to ask for help. I will try to respond as soon as possible.
Where do we go now?
You can browse through the recent articles or go to the archive for older items.
There are 8 comments for this article
Niels Matthijs on Dec 23, 2008
Good little write-up. I remember those days at the drawing table, how many hairs were lost in battle.
Two small remarks:
R Dvorak on Mar 3, 2009
Is it possible to separate the columns in the gridTwoRight example so that the background is visible between the two columns?
stringy on Jul 24, 2009
Thanks, this works really well for me!
neyronius on Jul 27, 2009
Nice solution! Very simple and effective!
stringy on Jul 29, 2009
Although I have just noticed, that if you put content into the example page, it doesn't work as expected in IE6. The following setups (TwoLeft with padding, TwoLeft with padding and border, and TwoRight with padding and border) don't seem to display properly, although the first and last ones are fine. I had a similar problem with TwoRight/IE6 in my version.
samuraijack on Nov 19, 2009
Hm.. but it seems this layout can't be nested?
SamuraiJack on Nov 19, 2009
Is it possible to implement a percentage width in this way?
cortney on Dec 21, 2009
I think the layout can be nested it just depends on the way its added. Don't put any hidden code in it, because chances are the page will get screwed up.