To build on top of bobince's answer:
Erik Arvidsson came up with a way to (kinda, sorta) add box-sizing support to IE6/IE7. However, his solution doesn't support units other than px
. Like you, I needed a percentage height, so I added support for percents.
Once you've downloaded and unzipped the zip file, open boxsizing.htc and replace the following border/padding functions:
/* border width getters */
function getBorderWidth(el, sSide) {
if (el.currentStyle["border" + sSide + "Style"] == "none")
return 0;
var n = parseInt(el.currentStyle["border" + sSide + "Width"]);
return n || 0;
}
function getBorderLeftWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Left"); }
function getBorderRightWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Right"); }
function getBorderTopWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Top"); }
function getBorderBottomWidth() { return getBorderWidth((arguments.length > 0 ? arguments[0] : element), "Bottom"); }
/* end border width getters */
/* padding getters */
function getPadding(el, sSide) {
var n = parseInt(el.currentStyle["padding" + sSide]);
return n || 0;
}
function getPaddingLeft() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Left"); }
function getPaddingRight() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Right"); }
function getPaddingTop() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Top"); }
function getPaddingBottom() { return getPadding((arguments.length > 0 ? arguments[0] : element), "Bottom"); }
/* end padding getters */
Then replace updateBorderBoxWidth
and updateBorderBoxHeight
with the following:
function updateBorderBoxWidth() {
element.runtimeStyle.width = "";
if (getDocumentBoxSizing() == getBoxSizing())
return;
var csw = element.currentStyle.width;
var w = null;
if (csw != "auto" && csw.indexOf("px") != -1) {
w = parseInt(csw);
} else if (csw != "auto" && csw.indexOf("%") != -1) {
var origDisplay = element.runtimeStyle.display;
element.runtimeStyle.display = "none";
w = Math.max(0, (parseInt(element.parentNode.clientWidth) - (
getBorderLeftWidth(element.parentNode)
+ getPaddingLeft(element.parentNode)
+ getPaddingRight(element.parentNode)
+ getBorderRightWidth(element.parentNode)
)) * (parseInt(csw) / 100));
element.runtimeStyle.display = origDisplay;
}
if (w !== null) {
if (getBoxSizing() == "border-box") {
setBorderBoxWidth(w);
} else {
setContentBoxWidth(w);
}
}
}
function updateBorderBoxHeight() {
element.runtimeStyle.height = "";
if (getDocumentBoxSizing() == getBoxSizing())
return;
var csh = element.currentStyle.height;
var h = null;
if (csh != "auto" && csh.indexOf("px") != -1) {
h = parseInt(csh);
} else if (csh != "auto" && csh.indexOf("%") != -1) {
var origDisplay = element.runtimeStyle.display;
element.runtimeStyle.display = "none";
h = Math.max(0, (parseInt(element.parentNode.clientHeight) - (
getBorderTopWidth(element.parentNode)
+ getPaddingTop(element.parentNode)
+ getPaddingBottom(element.parentNode)
+ getBorderBottomWidth(element.parentNode)
)) * (parseInt(csh) / 100));
element.runtimeStyle.display = origDisplay;
}
if (h !== null) {
if (getBoxSizing() == "border-box") {
setBorderBoxHeight(h);
} else {
setContentBoxHeight(h);
}
}
}
Then just use the file as you would otherwise:
.border-box {
behavior: url("boxsizing.htc");
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
Here's a pretty thorough test I put together while developing my modifications:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>box-sizing: border-box;</title>
<style type="text/css">
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: yellow;
}
body {
padding-top: 50px;
padding-bottom: 50px;
}
p {
margin: 0;
}
#header, #footer {
height: 50px;
position: absolute;
width: 100%;
overflow: hidden;
}
#header {
background: red;
top: 0;
}
#footer {
background: blue;
bottom: 0;
}
#content {
width: 100%;
height: 100%;
border: none;
margin: 0;
padding: 0;
background: black;
color: white;
overflow: auto;
position: relative;
padding-top: 40px;
padding-bottom: 40px;
}
#nested-header, #nested-footer {
position: absolute;
height: 40px;
width: 100%;
background: #CCC;
}
#nested-header {
top: 0;
}
#nested-footer {
bottom: 0;
}
#nested-content-wrap {
height: 100%;
}
#nested-floater {
height: 100%;
float: left;
width: 100px;
}
#nested-content {
height: 100%;
background: green;
color: black;
overflow: auto;
position: relative;
}
#inner-nest {
height: 100%;
position: relative;
}
#inner-head {
height: 30px;
width: 100%;
background: #AAA;
position: absolute;
top: 0;
}
#inner-content {
padding-top: 30px;
height: 100%;
overflow: auto;
}
.border-box {
behavior: url("boxsizing.htc");
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
}
.content-box {
behavior: url("boxsizing.htc");
box-sizing: content-box;
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box;
}
legend {
color: black;
}
form {
margin: 1em 0;
}
.wrap {
height: 100px;
background: #000;
overflow: hidden;
}
.test {
width: 100px;
height: 100%;
background: #AAA;
border-color: #EEE;
padding-left: 20px;
padding-top: 20px;
padding-bottom: 5px;
float: left;
}
.fill {
width: 100%;
height: 100%;
background: #CCC;
}
.gauge {
width: 99px;
background: white;
border-right: 1px solid green;
height: 100%;
float: left;
}
.notes {
background: #8FC561;
}
.clear {
clear: both;
}
/* 120px x 120px square; this will create a black 20px frame on the inside */
.boxtest-wrapper {
width: 100px;
height: 100px;
float: left;
background: black;
color: white;
margin: 1em;
padding: 20px;
}
#boxtest-4-container {
width: 100%;
height: 100%;
}
.boxtest {
width: 100%;
height: 100%;
background: white;
color: black;
border: 5px solid green;
overflow: hidden;
}
</style>
<script type="text/javascript">
function addBorderBox() {
var wrap1 = document.getElementById("wrap-1");
var wrap2 = document.getElementById("wrap-2");
var borderBox = document.createElement("div");
borderBox.className = "test border-box";
var borderBoxFill = document.createElement("div");
borderBoxFill.className = "fill";
var borderBoxContent = document.createTextNode("Generated border box fill");
borderBoxFill.appendChild(borderBoxContent);
borderBox.appendChild(borderBoxFill);
var gauge = document.createElement("div");
gauge.className = "gauge";
var gaugeText1 = "width: 100px";
var gaugeText2 = "height: 100%";
var gaugeText3 = "bottom should be visible";
gauge.appendChild(document.createTextNode(gaugeText1));
gauge.appendChild(document.createElement("br"));
gauge.appendChild(document.createTextNode(gaugeText2));
gauge.appendChild(document.createElement("br"));
gauge.appendChild(document.createTextNode(gaugeText3));
wrap1.appendChild(borderBox);
wrap2.appendChild(gauge);
}
</script>
</head>
<body id="body" class="border-box">
<div id="header">
<p>Header - 50px;</p>
</div>
<div id="content" class="border-box">
<div id="nested-header">
<p>Nested Header - 40px;</p>
</div>
<div id="nested-content-wrap">
<div id="nested-floater">
<p>Float - 100px;</p>
<ul>
<li>This element should never scroll.</li>
</ul>
</div>
<div id="nested-content">
<div id="inner-nest">
<div id="inner-head">
<p>Inner Head - 30px;</p>
</div>
<div id="inner-content" class="border-box">
<div style="float: right; ">
<p>The fourth square should look just like the other three:</p>
<div id="boxtest-wrapper-1" class="boxtest-wrapper">
<div id="boxtest-1" class="boxtest border-box"></div>
</div>
<div id="boxtest-wrapper-2" class="boxtest-wrapper">
<div id="boxtest-2" class="boxtest border-box"></div>
</div>
<br class="clear" />
<div id="boxtest-wrapper-3" class="boxtest-wrapper">
<div id="boxtest-3" class="boxtest border-box"></div>
</div>
<div id="boxtest-wrapper-4" class="boxtest-wrapper">
<div id="boxtest-4-container">
<!-- boxtest-4-container isn't special in any way. it just has width and height set to 100%. -->
<div id="boxtest-4" class="boxtest border-box"></div>
</div>
</div>
</div>
<p>Inner Content - fluid</p>
<ul>
<li>The top of the scrollbar should be covered by the “Inner Head” element.</li>
<li>The bottom of the scrollbar should be visible without having to scroll “Inner Head” out of view.</li>
</ul>
<p>Document Compat Mode:
<strong id="compatMode">
<script type="text/javascript">
var compatMode = document.compatMode;
if (compatMode != "CSS1Compat") {
document.getElementById("compatMode").style.color = "red";
}
document.write(compatMode);
</script>
</strong>
</p><br />
<div class="notes">
<h2>Notes</h2>
<ul>
<li>In IE6 and IE7 (and possibly IE8; untested), you'll notice a slight shift of contents that have <code>box-sizing</code> set to <code>border-box</code>. This is the amount of time it takes for <a href="box-sizing.htc">box-sizing.htc</a> to finish downloading.</li>
<li>This workaround is not live. Anything that causes a <a href="http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/">reflow or repaint</a> will not currently trigger an update to widths and heights of <code>border-box</code> elements.</li>
<li>See <a href="http://webfx.eae.net/dhtml/boxsizing/boxsizing.html">http://webfx.eae.net/dhtml/boxsizing/boxsizing.html</a> for the original solution to the IE6/IE7 <code>border-box</code> problem. <a href="box-sizing.htc">box-sizing.htc</a> has been modified to allow for percentage widths and heights.</li>
<li>To see what this example should look like without the use of <a href="box-sizing.htc">box-sizing.htc</a>, view it in Firefox or IE8.</li>
</ul>
</div>
<br class="clear" />
<form>
<fieldset>
<legend>DOM Update Test</legend>
<input type="button" value="Click to add border-box" onclick="addBorderBox(); " />
</fieldset>
</form>
<div id="wrap-1" class="wrap">
<div class="test content-box" id="content-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Content box fill</div>
</div>
<div class="test content-box" id="content-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Content box fill</div>
</div>
<div class="test border-box" id="border-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Border box fill</div>
</div>
<div class="test border-box" id="border-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Border box fill</div>
</div>
<div class="test" id="default-box-1" style="border-width: 5px; border-style: solid;">
<div class="fill">Default box fill</div>
</div>
<div class="test" id="default-box-2" style="border-width: 5px; border-style: solid; padding: 5px;">
<div class="fill">Default box fill</div>
</div>
</div>
<div id="wrap-2" class="wrap">
<!-- subtract 1 from width for 1px right border -->
<div class="gauge" style="width: 129px;">width: 130px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge" style="width: 119px;">width: 120px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge">width: 100px<br />height: 100%<br />bottom should be visible</div>
<div class="gauge">width: 100px<br />height: 100%<br />bottom should be visible</div>
<div class="gauge" style="width: 129px;">width: 130px<br />height: 100%<br />bottom should be cut off</div>
<div class="gauge" style="width: 119px;">width: 120px<br />height: 100%<br />bottom should be cut off</div>
</div>
<br class="clear" />
<script type="text/javascript">
var lipsum = "<p>Lorem ipsum dolor sit amet.</p>";
for (var i = 0; i < 100; i++) {
document.write(lipsum);
}
</script>
</div>
</div>
</div>
</div>
<div id="nested-footer">
<p>Nested Footer - 40px;</p>
</div>
</div>
<div id="footer">
<p>Footer - 50px;</p>
</div>
</body>
</html>