109

I have a little peculiar problem that I currently solve using a table, see below. Basically, I want to have two divs take up 100% of the available width, but only take up as much vertical space as needed (which isn't really that obvious from the picture). The two should at all times have the exact same height with a little line between them, as shown.

alt text
(source: pici.se)

This is all very easy to do using table, which I'm currently doing. However, I'm not too keen on the solution, as semantically this is not actually a table.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Deniz Dogan
  • 25,711
  • 35
  • 110
  • 162
  • 2
    Er... where is the picture? I know that I'm too late to comment on this – Ajay Kulkarni Jul 28 '15 at 13:45
  • Here is the image link from WebArchive.org [https://web.archive.org/web/20120617031534/http://pici.se/pictures/qJRMtoLPv.png](https://web.archive.org/web/20120617031534/http://pici.se/pictures/qJRMtoLPv.png) – DidThis Jun 05 '17 at 12:54

14 Answers14

166

You can get equal height columns in CSS by applying bottom padding of a large amount, bottom negative margin of the same amount and surrounding the columns with a div that has overflow hidden. Vertically centering the text is a little trickier but this should help you on the way.

#container {
  overflow: hidden;
      width: 100%;
}
#left-col {
  float: left;
  width: 50%;
  background-color: orange;
  padding-bottom: 500em;
  margin-bottom: -500em;
}
#right-col {
  float: left;
  width: 50%;
  margin-right: -1px; /* Thank you IE */
  border-left: 1px solid black;
  background-color: red;
  padding-bottom: 500em;
  margin-bottom: -500em;
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head></head>

<body>
  <div id="container">
    <div id="left-col">
      <p>Test content</p>
      <p>longer</p>
    </div>
    <div id="right-col">
      <p>Test content</p>
    </div>
  </div>
</body>

I think it worth mentioning that the previous answer by streetpc has invalid html, the doctype is XHTML and there are single quotes around the attributes. Also worth noting is that you dont need an extra element with clear on in order to clear the internal floats of the container. If you use overflow hidden this clears the floats in all non-IE browsers and then just adding something to give hasLayout such as width or zoom:1 will cause IE to clear its internal floats.

I have tested this in all modern browsers FF3+ Opera9+ Chrome Safari 3+ and IE6/7/8. It may seem like an ugly trick but it works well and I use it in production a lot.

starball
  • 20,030
  • 7
  • 43
  • 238
Natalie Downe
  • 3,036
  • 2
  • 20
  • 12
  • 1
    The code I gave validates at W3C's validator (well, once you add a element, which wasn't your point). Moreover, the specifications allow the use of single quotes according to this discussion: http://www.sitepoint.com/forums/showthread.php?t=54273#6 – instanceof me Jul 30 '09 at 10:57
  • 1
    Apologies, my mistake. I have amended my answer above. Point to note though, with your method, if the right column gets bigger than the left the red shows through underneath as the two boxes are not exactly the right height. Depending on the design I would opt for either faux columns or this method with the bottom margins and padding. – Natalie Downe Jul 30 '09 at 11:25
  • +1 for a great solution. If you're having issues with overFlow:hidden; hiding things (like a box-shadow), just add padding to the parent container. Adding overflow:hidden; also establishes a new Block Formatting Context. See http://colinaarts.com/articles/the-magic-of-overflow-hidden/ and http://www.w3.org/TR/CSS21/visuren.html#block-formatting for more information. – Kevin C. Jul 01 '11 at 21:32
  • 2
    Actually while the solution given by Kevin C. about shadows being cut off works for the top, left and right padding, it doesn't work for the bottom. Haven't found a solution so far. – JeanMertz Nov 03 '11 at 13:05
  • Here is someone who writes about some possible troubles with this method. http://www.positioniseverything.net/articles/onetruelayout/appendix/equalheightproblems. It's fairly old, talks about Firefox 1.5 and IE 6 — perhaps modern browsers work better. – KajMagnus Jun 19 '12 at 02:41
  • Natalie, Nice fix, but completely useless if you have a page of unpredictable height... Though probably the best solution I've seen so far. – laarsk Aug 03 '12 at 10:01
  • 1
    Nice work Natalie. @laarsk Unpredictable height is exactly what this is for isnt it ? See demo: http://jsfiddle.net/RT3MT/4/ move the "longer" paragraphs around to see – jpillora Jun 27 '13 at 06:02
  • 1
    This is one of the ugliest CSS hacks I've ever seen, but I'm going to embrace it with open arms lol. It seems to be the only way forward – Matt Vukas Oct 19 '14 at 21:01
  • Can someone please give a pointer or two on how to centre text within these auto-height adjusted divs? Thanks – rockhammer Mar 11 '16 at 04:40
  • On the second column, using `box-sizing: border-box;` instead of `margin-right: -1px;` works, on IE too (tested on IE9, I won't go lower than that...). – nonzaprej Oct 24 '17 at 08:12
  • Note that this method breaks rendering when used in combination with in-page anchor links, at least in Chrome. Everything above the anchor link will no longer be rendered after the user clicks to the anchor. If when using this hack the background-color overflows onto the following div, you can apply a higher z-index to the following div to correct. e.g. z-index: 2; position: relative; assuming the cols have z-index of 1 or less. – SeanFromIT Sep 21 '18 at 20:59
100

It is year 2012+n, so if you no longer care about IE6/7, display:table, display:table-row and display:table-cell work in all modern browsers:

http://www.456bereastreet.com/archive/200405/equal_height_boxes_with_css/

Update 2016-06-17: If you think time has come for display:flex, check out Flexbox Froggy.

Dmitry Leskov
  • 3,233
  • 1
  • 20
  • 17
22

You should use flexbox to achieve this. It's not supported in IE8 and IE9 and only with the -ms prefix in IE10, but all other browsers support it. For vendor prefixes, you should also use autoprefixer.

.parent {
    display: flex;
    flex-wrap: wrap; // allow wrapping items
}

.child {
    flex-grow: 1;
    flex-basis: 50%; // 50% for two in a row, 33% three in a row etc.
}
Luca Steeb
  • 1,795
  • 4
  • 23
  • 44
  • 1
    The problem I have with flex is that it needs a wrapper around the columns. With the floats + display:table technique I can have e.g. a header and a bunch of columns and the effect works on the columns without affecting the header. – Stijn de Witt May 28 '18 at 07:23
10

you can get this working with js:

<script>
    $(document).ready(function() {
        var height = Math.max($("#left").height(), $("#right").height());
        $("#left").height(height);
        $("#right").height(height);
    });
</script>
Andi P. Trix
  • 175
  • 1
  • 3
  • 1
    Please notice that this question is already quite old and better solutions (without the need of javascript) have already been provided. – nirazul Sep 17 '13 at 22:47
  • 1
    I actually like this solution. It's fun and shows that not only can you manipulate your html with css, but you can also do it with the help of jquery – csichar Feb 11 '15 at 17:37
  • 6
    This solution will not work if the height of the columns change. This could happen if content of the columns is changed. This function would need to be run: on content change and .on browser resize. The css approach is more ideal as it avoids these concerns – alexreardon Apr 20 '15 at 04:54
5

This is a classic problem in CSS. There's not really a solution for this.

This article from A List Apart is a good read on this problem. It uses a technique called "faux columns", based on having one vertically tiled background image on the element containing the columns that creates the illusion of equal-length columns. Since it is on the floated elements' wrapper, it is as long as the longest element.


The A List Apart editors have this note on the article:

A note from the editors: While excellent for its time, this article may not reflect modern best practices.

The technique requires completely static width designs that doesn't work well with the liquid layouts and responsive design techniques that are popular today for cross-device sites. For static width sites, however, it's a reliable option.

user56reinstatemonica8
  • 32,576
  • 21
  • 101
  • 125
Philippe Leybaert
  • 168,566
  • 31
  • 210
  • 223
  • Thank you, that seems like a nice hack. However, I forgot to mention that the right column should have text in it, vertically centered. Am I right in believing that faux columns can't do this? – Deniz Dogan Jul 30 '09 at 08:32
4

I had similar problem and in my opinion best option is to use just a little bit of javascript or jquery.

You can get wanted divs to be same height by getting highest div value and applying that value to all other divs. If you have many divs and many solutions i suggest to write little advance js code to find out which of all divs is the highest and then use it's value.

With jquery and 2 divs it's very simple, here is example code:

$('.smaller-div').css('height',$('.higher-div').css('height'));

And for the end, there is 1 last thing. Their padding (top and bottom) must be the same ! If one have larger padding you need to eliminate padding difference.

Mr Br
  • 3,831
  • 1
  • 20
  • 24
1

This works for me in IE 7, FF 3.5, Chrome 3b, Safari 4 (Windows).

Also works in IE 6 if you uncomment the clearer div at the bottom. Edit: as Natalie Downe said, you can simply add width: 100%; to #container instead.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <style type="text/css">
        #container {
            overflow: hidden;
            border: 1px solid black;
            background-color: red;
        }
        #left-col {
            float: left;
            width: 50%;
            background-color: white;
        }
        #right-col {
            float: left;
            width: 50%;
            margin-right: -1px; /* Thank you IE */
        }
    </style>
</head>
<body>
    <div id='container'>
        <div id='left-col'>
            Test content<br />
            longer
        </div>
        <div id='right-col'>
            Test content
        </div>
        <!--div style='clear: both;'></div-->
    </div>
</body>
</html>

I don't know a CSS way to vertically center the text in the right div if the div isn't of fixed height. If it is, you can set the line-height to the same value as the div height and put an inner div containing your text with display: inline; line-height: 110%.

instanceof me
  • 38,520
  • 3
  • 31
  • 40
1

As far as I know, you can't do this using current implementations of CSS. To make two column, equal height-ed you need JS.

Calin Don
  • 865
  • 2
  • 11
  • 19
1

Using Javascript, you can make the two div tags the same height. The smaller div will adjust to be the same height as the tallest div tag using the code shown below:

var rightHeight = document.getElementById('right').clientHeight;
var leftHeight = document.getElementById('left').clientHeight;
if (leftHeight > rightHeight) {
document.getElementById('right').style.height=leftHeight+'px';
} else {
document.getElementById('left').style.height=rightHeight+'px';
}

With "left" and "right" being the id's of the div tags.

Quintox303
  • 11
  • 1
1

By using css property --> display:table-cell

div {
    border: 1px solid #000;
    margin: 5px;
    padding: 4px;
 display:table-cell;
 width:25% ;position:relative;
}
body{display:table;
 border-collapse:separate;
 border-spacing:5px 5px}
<div>
    This is my div one This is my div one This is my div one
</div>
<div>
    This is my div two This is my div two This is my div two This is my div two This is my div two This is my div two
</div>
<div>
    This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3 This is my div 3
</div>
0

Using JS, use data-same-height="group_name" in all the elements you want to have the same height.

The example: https://jsfiddle.net/eoom2b82/

The code:

$(document).ready(function() {
    var equalize = function () {
        var disableOnMaxWidth = 0; // 767 for bootstrap

        var grouped = {};
        var elements = $('*[data-same-height]');

        elements.each(function () {
            var el = $(this);
            var id = el.attr('data-same-height');

            if (!grouped[id]) {
                grouped[id] = [];
            }

            grouped[id].push(el);
        });

        $.each(grouped, function (key) {
            var elements = $('*[data-same-height="' + key + '"]');

            elements.css('height', '');

            var winWidth = $(window).width();

            if (winWidth <= disableOnMaxWidth) {
                return;
            }

            var maxHeight = 0;

            elements.each(function () {
                var eleq = $(this);
                maxHeight = Math.max(eleq.height(), maxHeight);
            });

            elements.css('height', maxHeight + "px");
        });
    };

    var timeout = null;

    $(window).resize(function () {
        if (timeout) {
            clearTimeout(timeout);
            timeout = null;
        }

        timeout = setTimeout(equalize, 250);
    });
    equalize();
});
Wiliam
  • 3,714
  • 7
  • 36
  • 56
0

I needed to do something similar, here is my implementation. To recap the purpose, it is to have 2 elements take up the width of a given parent container, and the height to only be as high as it needs to be. Essentially height equaling max height of largest amount of content, but the other container being flush.

html

<div id="ven">
<section>some content</section>
<section>some content</section>
</div>

css

#ven {
height: 100%;
}
#ven section {
width: 50%;
float: left;
height: 100%;
}
this guy
  • 1
  • 1
0

Several years ago, the float property used to solve that problem with the table approach using display: table; and display: table-row; and display: table-cell;.

But now with the flex property, you can solve it with 3 lines of code: display: flex; and flex-wrap: wrap; and flex: 1 0 50%;

.parent {
    display: flex;
    flex-wrap: wrap;
}

.child {
 // flex: flex-grow flex-shrink flex-basis;
    flex: 1 0 50%;
}

1 0 50% are the flex values we gave to: flex-grow flex-shrink flex-basis respectively. It's a relatively new shortcut in flexbox to avoid typing them individually. I hope this helps someone out there

Fouad Boukredine
  • 1,495
  • 14
  • 18
0

Considering Natalie's response, it seemed very good, but I had problems with a possible footer area, which could be hacked a little using clear: both.

Of course, a better solution would be to use flexbox or grid nowadays.

You can check this codepen if you want.

enter image description here

.section {
  width: 500px;
  margin: auto;
  overflow: hidden;
  padding: 0;
}

div {
  padding: 1rem;
}

.header {
  background: lightblue;
}

.sidebar {
  background: lightgreen;
  width: calc(25% - 1rem);
}

.sidebar-left {
  float: left;
  padding-bottom: 500rem;
  margin-bottom: -500rem;
}

.main {
  background: pink;
  width: calc(50% - 4rem);
  float: left;
  padding-bottom: 500rem;
  margin-bottom: -500rem;
}

.sidebar-right {
  float: right;
  padding-bottom: 500rem;
  margin-bottom: -500rem;
}

.footer {
  background: black;
  color: white;
  float: left;
  clear: both;
  margin-top: 1rem;
  width: calc(100% - 2rem);
}
<div class="section">
<div class="header">
  This is the header
</div>
<div class="sidebar sidebar-left">
  This sidebar could have a menu or something like that. It may not have the same length as the other
</div>
<div class="main">
  This is the main area. It should have the same length as the sidebars
</div>
<div class="sidebar sidebar-right">
  This is the other sidebar, it could have some ads
</div>
<div class="footer">
  Footer area
</div>
</div>
Adriano_Pinaffo
  • 1,429
  • 4
  • 23
  • 46