This is another Blog about HTML Element Dimensions. It contains JavaScript (JS) functions to calculate the outer and inner width of elements, and to set these dimensions accordingly. I will cover block
and inline-block
elements (but not inline
elements), and the infamous box-sizing CSS property.
Mind that my usage of the terms outer and inner for width and height differs from the jQuery meanings for outer and inner. While jQuery's .outerWidth()
delivers element.offsetWidth (optionally including margin), and .innerWidth()
delivers element.clientWidth, my understanding of "inner" is the usable element space within, i.e. the inner rectangle without padding
, and with "outer" I describe the space an element would take as a whole, i.e. including margin
.
The reason why I won't cover inline
elements is that these can not be resized by setting CSS width
and height
. If you want to size a SPAN, you need to set it display: inline-block
, or its position: fixed
or absolute
. Further inline
elements do not include top and bottom margins into their height (will be painted over other elements when used), while they do include left and right margins into their width.
Here is some test HTML. Four different DIV elements are arranged vertically, the first two have box-sizing: content-box
, the second two box-sizing: border-box
. The third element has display: inline-block
, all others are display: block
(DIV default). All four elements have different margins, borders and paddings.
It is easy to visualize a border, you just need to give it a width and a colour. To visualize margins and paddings is not so easy. Thus I decided to enclose each demo element into a DIV wrapper that has display: inline-block
(does not expand to whole width) and a dotted black border. This will visualize the margin as the space between the coloured and the dotted black border. To visualize the padding, I nested a DIV element into the demo DIV, which has 100% height to always fill up its parent entirely, and a yellow background colour. Thus it renders the padding as the space between the yellow area and the coloured border.
The challenge now is to set all these demo elements to same size. As I talked about inner and outer size, both can be done here:
Pixels
Right-click on an element and trigger "Inspect Element" to see what your browser debugger displays as "Box Model". You need to focus the element with CSS class sameSize
, not its parent or child (which are just for visualizing margin and padding).
Click on left arrow to see the demo HTML and CSS.
1 | <!DOCTYPE html> |
Here comes the JS source code working in this demo. First the module frame:
var elementDimensions = (function()
{
"use strict";
var self = {};
.....
return self;
})();
The page-gobal variable elementDimensions
evaluates to a singleton object created from an immediately invoked function expression(IIFE). A function that creates an object (or a function) containing inner functions is called "module" in JS.
All following JS source goes to where the "...." is.
self.getInnerSize = function(element) {
return {
width: self.getInnerWidth(element),
height: self.getInnerHeight(element)
};
};
self.getInnerWidth = function(element) {
var style = window.getComputedStyle(element);
var borderWidth = window.parseInt(style["border-left-width"]) + window.parseInt(style["border-right-width"]);
var paddingWidth = window.parseInt(style["padding-left"]) + window.parseInt(style["padding-right"]);
return element.offsetWidth - borderWidth - paddingWidth;
};
self.getInnerHeight = function(element) {
var style = window.getComputedStyle(element);
var borderHeight = window.parseInt(style["border-top-width"]) + window.parseInt(style["border-bottom-width"]);
var paddingHeight = window.parseInt(style["padding-top"]) + window.parseInt(style["padding-bottom"]);
return element.offsetHeight - borderHeight - paddingHeight;
};
self.getOuterSize = function(element) {
return {
width: self.getOuterWidth(element),
height: self.getOuterHeight(element)
};
};
self.getOuterWidth = function(element) {
var style = window.getComputedStyle(element);
var marginWidth = window.parseInt(style["margin-left"]) + window.parseInt(style["margin-right"]);
return element.offsetWidth + marginWidth;
};
self.getOuterHeight = function(element) {
var style = window.getComputedStyle(element);
var isInlineElement = (style.display === "inline");
var marginHeight = isInlineElement ? 0 : window.parseInt(style["margin-top"]) + window.parseInt(style["margin-bottom"]);
return element.offsetHeight + marginHeight;
};
For the inner width and height we can ignore box-sizing
, it will be the same for content-box
and border-box
. Simply subtract the padding and border from offsetWidth
. This would also work for inline
elements. Although they do not have a clientWidth
, their offsetWidth
should always be present when they are visible.
The same applies to outer width and height. We simply add margins to offsetWidth
. Just when it is an inline
element, we must not add them when calculating the height the element claims.
self.setInnerSize = function(element, innerWidth, innerHeight) {
self.setInnerWidth(element, innerWidth);
self.setInnerHeight(element, innerHeight);
};
self.setInnerWidth = function(element, innerWidth) {
var style = window.getComputedStyle(element);
var cssWidth = innerWidth;
if (style["box-sizing"] === "border-box") {
var borderWidth = window.parseInt(style["border-left-width"]) + window.parseInt(style["border-right-width"]);
cssWidth += borderWidth;
var paddingWidth = window.parseInt(style["padding-left"]) + window.parseInt(style["padding-right"]);
cssWidth += paddingWidth;
}
if (cssWidth > 0)
element.style["width"] = cssWidth+"px";
};
self.setInnerHeight = function(element, innerHeight) {
var style = window.getComputedStyle(element);
var cssHeight = innerHeight;
if (style["box-sizing"] === "border-box") {
var borderHeight = window.parseInt(style["border-top-width"]) + window.parseInt(style["border-bottom-width"]);
cssHeight += borderHeight;
var paddingHeight = window.parseInt(style["padding-top"]) + window.parseInt(style["padding-bottom"]);
cssHeight += paddingHeight;
}
if (cssHeight > 0)
element.style["height"] = cssHeight+"px";
};
self.setOuterSize = function(element, outerWidth, outerHeight) {
self.setOuterWidth(element, outerWidth);
self.setOuterHeight(element, outerHeight);
};
self.setOuterWidth = function(element, outerWidth) {
var style = window.getComputedStyle(element);
var marginWidth = window.parseInt(style["margin-left"]) + window.parseInt(style["margin-right"]);
var cssWidth = outerWidth - marginWidth;
if (style["box-sizing"] !== "border-box") {
var borderWidth = window.parseInt(style["border-left-width"]) + window.parseInt(style["border-right-width"]);
cssWidth -= borderWidth;
var paddingWidth = window.parseInt(style["padding-left"]) + window.parseInt(style["padding-right"]);
cssWidth -= paddingWidth;
}
if (cssWidth > 0)
element.style["width"] = cssWidth+"px";
};
self.setOuterHeight = function(element, outerHeight) {
var style = window.getComputedStyle(element);
var marginHeight = window.parseInt(style["margin-top"]) + window.parseInt(style["margin-bottom"]);
var cssHeight = outerHeight - marginHeight;
if (style["box-sizing"] !== "border-box") {
var borderHeight = window.parseInt(style["border-top-width"]) + window.parseInt(style["border-bottom-width"]);
cssHeight -= borderHeight;
var paddingHeight = window.parseInt(style["padding-top"]) + window.parseInt(style["padding-bottom"]);
cssHeight -= paddingHeight;
}
if (cssHeight > 0)
element.style["height"] = cssHeight+"px";
};
Writing dimensions is more complex. We need to consider the box-sizing
CSS property. When we want to set the inner width of an element with box-sizing: border-box
, we need to add its border and padding to the given size.
Symmetrically we need to subtract the border and padding from given size when setting the outer width of an element with box-sizing: content-box
.
Remember:
width
on box-sizing: border-box
is the same as offsetWidth
, but for box-sizing: content-box
(default), offsetWidth
includes border and padding. Margins are never included, neither in clientWidth
nor offsetWidth
.For the current state of this utility go to my homepage.
ɔ⃝ Fritz Ritzberger, 2016-04-11