HTML/CSS: 使两个浮动 div 具有相同的高度

我有一个小特殊的问题,我目前解决使用 table,见下文。基本上,我希望有两个 div 占用100% 的可用宽度,但只占用尽可能多的垂直空间,因为需要(这是不是真的很明显,从图片)。如图所示,两者在任何时候都应该具有完全相同的高度,两者之间应该有一条小线。

alt text
(来源: Pici.se)

这一切都很容易做到使用 table,我目前正在这样做。然而,我不太热衷于解决方案,因为从语义上讲,它实际上不是一个表。

214523 次浏览

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.

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%.

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.

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.

I hope this helps.

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.

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.

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>

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.

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();
});

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.
}

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>

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%;
}

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

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>