As discussed in the article "Faux Columns" by Dan Cederholm [1], "elements only stretch vertically as far as they need to" (rendered in standards-compliant mode).
Eric A. Meyers "Cascading Style Sheets" [2] is instructive to me on this matter. In Chapter 10 "Floating and Positioning: Negative margins" a discussion of what happens when negative values for positioning are used in floated elements reveals that there is a shifting "content edge", and remarkably, an "outer edge" which stays the same, keeping it's position as if it were not shifted.
The idea is to swap both columns, the right one to the left, the left one to the right: Note, when we shift a column to the right, the "outer edge" will remain on the left-hand side and vice versa. Therefore, the "outer edge" and the "content edge" of one column will stretch both containers. So, no matter which of the columns is the taller, the tallest will stretch both containers!
This can be done in CSS in standards-compliant mode, without too many browser specific hacks. All paragraphs should be placed in sequence order to assist screen-readers, along with a sizeable width for zooming the text. Each column should have the ability to have its own background-setting.
We need a wrapper, sized using ems in horizontal direction, wide enough to hold two columns and a dividing space in the middle (Fig. 1).
Its first child, .containerRight (Fig. 2), is a right-floater, its second child, .containerLeft (Fig. 3), is a left-floater.
The column is a child of the container, positioned relative (Fig. 4). So what happens if we shift it to the other side with the property "left"? The "outer edge" will stay on the right of the column, stretching the container by the columns calculated height (Fig. 5).
So when swapping both columns to their other side (Fig. 6a, 6b, 7) they remain with their "outer edge". Since the shifted "content edge" of the tallest column overlaps the non-shifted "outer edge" of the container on its side both columns are stretched. Therefore, as a consequence of the overlapping, both columns are now shown at equal height.
It's an em-based design, as I didn't manage an exact cross-browser shifting version using percentages, though a px-fixed layout should work too. There is no need for any background setting. Also, a shifting method using margin-left should be possible if needed.
Opera7.54 needs z-indexes for the columns: Without them, the background of the column-container is patched over the shifted column, that's bad render sequencing ... (Fig. 8). The shifting works for each column, but together, the container planes were drawn in order of the markup after the shifting. In IEWin/Mozilla, this is the behaviour when both containers are given {position: relative;}.
IE mac needs a hack: when applying {left: 22em;} to .columnShiftToRight, as the .containerLeft expands in width. Therefore, in order to fix this, {display: inline-block} (CSS2.1) is presented to IE mac only. The columns, shifted by the use of the property "left:", need {overflow:auto} to prevent the shifting on nested elements [3].
Many thanks to Big John at Position is Everything for a site review and for encouraging me, and to Philippe Wittenbergh at La Chatte Noire for his invaluable Mac engineering and fixing.
Thanks to David Batty for corrections.
Arnau Siches explains the method in Catalan: Igualant columnes.
We're discussing the needs of two columns with different em-width. IE6 ("standards" mode), FF1+, Op8 are fine. It breaks IE5Mac, though: column-swapping, revisited
Companion column method is a new, different approach for the old problem.
Last updated: July 10, 2007
Created: August 5, 2004
Any ideas, workarounds, comments and corrections are appreciated. Note that this method hasn't been tested for production sites yet, the status of this document is still "draft, experimental". Please report your stress testing of this method to: info at satzansatz dot de.
Ingo Chao
.wrapper{
margin: 0 auto;
width: 42em;
background: #f2f2f2;
}
.containerRight{
width: 20em;
background: #ffedc7
url(swapborder_r.png)
repeat-y left;
float:right;
}
<div class="wrapper">
<div class="containerRight">
...
</div>
</div>
.containerLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
float:left;
}
<div class="wrapper">
<div class="containerRight">
...
</div>
<div class="containerLeft">
...
</div>
</div>
.columnShiftToLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
/* left: -22em; */
/* not shifted in this Fig.*/
position: relative;
z-index:1;
}
<div class="wrapper">
<div class="containerRight">
<div class="columnShiftToLeft">
...
</div>
</div>
<div class="containerLeft">
...
</div>
</div>
.columnShiftToLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
left: -22em;
/* shifted */
position: relative;
z-index: 1;
}
<div class="wrapper">
<div class="containerRight">
<div class="columnShiftToLeft">
...
</div>
</div>
<div class="containerLeft">
...
</div>
</div>
shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - END
.columnShiftToLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
left: -22em;
position: relative;
z-index: 1;
}
shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - END
.columnShiftToRight{
width: 20em;
background: #ffedc7
url(swapborder_r.png)
repeat-y left;
left: 22em;
position: relative;
z-index: 2;
}
<div class="wrapper">
<div class="containerRight">
<div class="columnShiftToLeft">
...
</div>
</div>
<div class="containerLeft">
<div class="columnShiftToRight">
...
</div>
</div>
</div>
shifted content - right - - END
.columnShiftToLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
left: -22em;
position: relative;
z-index: 1;
}
shifted content - left - END
.columnShiftToRight{
width: 20em;
background: #ffedc7
url(swapborder_r.png)
repeat-y left;
left: 22em;
position: relative;
z-index: 2;
}
<div class="wrapper">
<div class="containerRight">
<div class="columnShiftToLeft">
...
</div>
</div>
<div class="containerLeft">
<div class="columnShiftToRight">
...
</div>
</div>
</div>
shifted content - right - END
body {
margin: 2.5% 0 2.5% 0;
background-color:#F2F2F2;
font-family: sans-serif;
}
.ccontainweb {
width:100%;
text-align:center;
background-color:#F2F2F2;
margin:0;
padding:0;
}
.ccontainpage {
padding: 2% 2.5% 3% 2.5%;
margin:0 auto;
width:90%;
text-align:left;
background-color:#FFFCF5;
border: 1px solid #8F8F8F;
}
.wrapper{
margin: 0 auto;
width:42em;
background: #f2f2f2;
}
.header{
margin-bottom: 1em;
text-align:center;
background:#ddd;
}
.footer{
margin-top: 1em;
background:#ddd;
}
.containerRight{
width: 20em;
background: #ffedc7
url(swapborder_r.png)
repeat-y left;
float:right;
}
.columnShiftToLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
left: -22em;
position: relative;
z-index:1; /* Opera7.54 */
}
/* IE mac hack */
* html>body .columnShiftToLeft {
overflow: auto;
}
.containerLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
float:left;
}
.columnShiftToRight{
width: 20em;
background: #ffedc7
url(swapborder_r.png)
repeat-y left;
left:22em;
position: relative;
z-index:2; /* Opera7.54 */
}
/* IE mac hack */
* html>body .columnShiftToRight{
display:inline-block;
overflow: auto;
}
.content{
padding: 1em;
line-height: 125%;
}
.brclear {
clear:both;
height:0;
margin:0;
font-size: 1px;
line-height: 0;
}
<body>
<div class="ccontainweb">
<div class="ccontainpage">
<div class="wrapper">
<div class="header">
<div class="content">
...
</div>
</div>
<div class="containerRight">
<div class="columnShiftToLeft">
<div class="content">
...
</div>
</div>
</div>
<div class="containerLeft">
<div class="columnShiftToRight">
<div class="content">
...
</div>
</div>
</div>
<br class="brclear" />
<div class="footer">
<div class="content">
...
</div>
</div>
</div>
</div>
</div>
</body>
.wrapper{
margin: 0 auto;
width: 40em;
background: #f2f2f2;
}
.columnShiftToLeft{
width: 20em;
background: #ffedc7
url(swapborder_l.png)
repeat-y right;
left: -20em;
position: relative;
z-index:1;
}
* html>body .columnShiftToLeft {
overflow: auto;
}
.columnShiftToRight{
width: 20em;
background: #ffedc7
url(swapborder_r.png)
repeat-y left;
left: 20em;
position: relative;
z-index:2;
}
/* IE mac hack */
* html>body .columnShiftToRight{
display:inline-block;
overflow: auto;
}
shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - shifted content - left - - END