While trying to implement a resizable panel in vanilla JS, trouble started showing up when the panel had scrollbars. I made this test fiddle and to my surprise, the panel became smaller instead of bigger when I added to its width.
I recommend viewing it on JSFiddle here http://jsfiddle.net/y3m9Lo17/ but here's the code on SO as well.
getInnerWidth = function (elem) {
return parseFloat(window.getComputedStyle(elem).width);
};
getExternalWidth = function (elem) {
return elem.offsetWidth - getInnerWidth(elem);
};
setTotalWidth = function (elem, width) {
elem.style.width = (width - getExternalWidth(elem)) + "px";
};
getInnerHeight = function (elem) {
return parseFloat(window.getComputedStyle(elem).height);
};
getExternalHeight = function (elem) {
return elem.offsetHeight - getInnerHeight(elem);
};
setTotalHeight = function (elem, height) {
elem.style.height = (height - getExternalHeight(elem)) + "px";
};
//===========================================================================================
var container = document.getElementById("container");
var content = document.getElementById("content");
minus10css = function () {
container.style.width = (getInnerWidth(container) - 10) + "px";
};
equal200css = function () {
container.style.width = "200px";
};
plus10css = function () {
container.style.width = (getInnerWidth(container) + 10) + "px";
};
minus10 = function () {
setTotalWidth(container, container.offsetWidth - 10);
};
equal200 = function () {
setTotalWidth(container, 200);
};
plus10 = function () {
setTotalWidth(container, container.offsetWidth + 10);
};
cssCalc = function () {
content.style.height = "calc(100% - 30px)";
};
total300 = function() {
setTotalHeight(content, 300);
};
css300 = function() {
content.style.height = "300px";
};
#container {
background-color: yellow;
width: 200px;
height: 300px;
overflow-y: auto;
}
#content {
background-color: blue;
background: -webkit-linear-gradient(green, blue);
background: -moz-linear-gradient(green, blue);
background: -o-linear-gradient(green, blue);
background: linear-gradient(green, blue);
width: calc(100% - 30px);
margin: 5px;
height: calc(100% - 30px);
color: white;
padding: 10px;
}
<div id="container">
<div id="content">
This element is set to have exactly his parent's width minus its margins
and paddings thanks to the CSS calc function, so it should fit perfectly
even when resized.
</div>
</div>
<br />
<p>CSS width of container:
<br />
<button onclick="minus10css()">-=10</button>
<button onclick="equal200css()">=200</button>
<button onclick="plus10css()">+=10</button>
</p>
<p>Total width of container:
<br />
<button onclick="minus10()">-=10</button>
<button onclick="equal200()">=200</button>
<button onclick="plus10()">+=10</button>
</p>
<p><b style="color: red;">Content height</b>
<br />
<button onclick="cssCalc()">css calc fit</button>
<button onclick="total300()">total 300</button>
<button onclick="css300()">css 300</button>
</p>
<p>Get info<br />
<button onclick="alert(container.style.width)">css container width</button>
<button onclick="alert(getInnerWidth(container))">inner container width</button>
</p>
I then made another test and found out that the width returned by getComputedStyle is actually the CSS width minus the width of a scrollbar.
document.getElementById("cssWidth").innerHTML = "CSS width = " + document.getElementById("container").style.width;
document.getElementById("computedWidth").innerHTML = "getComputedStyle width = " + window.getComputedStyle(document.getElementById("container")).width;
#container {
background-color: yellow;
overflow-y: auto;
}
#content {
background-color: blue;
background: -webkit-linear-gradient(green, blue);
background: -moz-linear-gradient(green, blue);
background: -o-linear-gradient(green, blue);
background: linear-gradient(green, blue);
width: 100%;
height: 200%;
color: white;
}
<div id="container" style="width: 200px; height: 200px;">
<div id="content">This element is set to have exactly his parent's width minus its margins and paddings thanks to the CSS calc function, so it should fit perfectly even when resized.</div>
</div>
<span id="cssWidth"></span><br />
<span id="computedWidth"></span>
But I can't use the elem.style.width property since the initial value could be a percentage or a calc() css function, and is set through a class (not on the element itself, so the element.style property won't have it). Is there any way to "fix" this Chrome behavior so I get 200px? EDIT: this is also a problem in IE, but Firefox returns the true CSS width.
EDIT: if you don't have chrome to test this, look at this fiddle: http://jsfiddle.net/y8Y32/25/ Chrome's getComputedStyle width is equal to the width of the first paragraph.