Controlling the Geometry of an HTML Element

By Jochen Voss, last updated 2011-08-31

This page discusses how the get and set the size of an element in an HTML page. Some general information about how to use CSS and JavaScript in an HTML page can be found on my page about HTML5 apps.

Contents

Introduction

The geometry of most HTML elements is controlled by the CSS Box Model. Elements are assumed to be rectangular, being surrounded by some (transparent) margin and possibly a border. For container elements, there is also an inner margin, called padding, which keeps child elements at a certain distance from the container boundaries.

[illustration of the CSS margins]

Figure 1. Illustration of the (horizontal) margin, border-width and padding in the CSS box model. The corresponding vertical quantities are arranged analogously.

The relevant quantites, from the outside in, are

Reading Geometry Parameters

There are two ways to read out the various parameters governing the geometry of an HTML element: Some of the parameters are exposed as properties of the JavaScript objects representing the elements. Alternatively, the parameters can be accessed by reading the computed CSS style information.

Some care is needed, since the returned values are not always identical to the values given in the style sheet. For example, sometimes browsers seem to round border widths to an integer number of screen pixels, and with non-standard zoom levels the returned (CSS pixel) values are then fractional values, slightly different from what was given in the style sheet.

Using Object Properties

The top part of table 1 lists the available parameters. The visual height of an object can, for example, be computed using code like the following:

var box = document.getElementById("mybox");
var clientWidth = box.clientWidth;

For the yellow box from the example in figure 2 the result is clientWidth = 12 + 282 + 6 = 300. This method allows to obtain the regions delimited by the inner and outer edges of the element border. It does not offer any information about margins or padding.

Figure 2. The test element we use for the example in the text. The yellow rectangle is a DIV element with the following CSS style applied to it

width: 282px;
border: solid black;
background: yellow;
margin: 1px 4px 7px 10px;
border-width: 2px 5px 8px 11px;
padding: 3px 6px 9px 12px;

Contained in this element is a green square, implemented as a DIV of size 100×100 and without any margin, borders or padding.

Using the Computed CSS Style

The computed CSS information can be obtained using the window.getComputedStyle function, using code like the following. The top part of table 1 lists the available parameters. Since the returned values are strings of the form 12px, we need to convert the return values to numbers. This can be done using the parseFloat function (which ignores the trailing px).

var box = document.getElementById("mybox");
var style = window.getComputedStyle(box,null);
var pl = parseFloat(style.getPropertyValue("padding-left"));
Google Chrome
5.0.375.55
MacOS X
Firefox
3.6.3
MacOS X

object properties

offsetWidth 316 316
scrollWidth 300 316
clientWidth 300 300
offsetHeight 122 122
scrollHeight 112 122
clientHeight 112 112
clientTop 2 2
clientLeft 11 11

computed CSS style

width 282px 282px
height 100px 100px
margin-top 1px 1px
border-top-width 2px 2px
padding-top 3px 3px
margin-right * 4px
border-right-width 5px 5px
padding-right 6px 6px
margin-bottom 7px 7px
border-bottom-width 8px 8px
padding-bottom 9px 9px
margin-left 10px 10px
border-left-width 11px 11px
padding-left 12px 12px

Table 1. The dimensions of the yellow rectangle in figure 2 as obtained by different browsers. The given value are for the default zoom-level.

Changing Geometry Parameters

Since the DOM object properties listed in the top part of table 1 are read-only, object geometry can only be changed by changing the CSS style information of an object directly.

Example 1. Code like the following can be used to make an element big enough to contain a child element of a given width.

var childWidth = 100;
var box = document.getElementById("mybox");
box.style.paddingLeft = childWidth+"px";

Example 2. The following code changes the element size so that it will take up a given width in the parent container.

var parentWidth = 100;
var box = document.getElementById("mybox");
var style = window.getComputedStyle(box,null);
var ml = parseFloat(style.getPropertyValue("margin-left"));
var bl = parseFloat(style.getPropertyValue("border-left-width"));
var pl = parseFloat(style.getPropertyValue("padding-left"));
var pr = parseFloat(style.getPropertyValue("padding-rigth"));
var br = parseFloat(style.getPropertyValue("border-rigth-width"));
var mr = parseFloat(style.getPropertyValue("margin-rigth"));
box.style.paddingLeft = (parentWidth-ml-bl-pl-pr-br-mr)+"px";

Example

This section gives an extensive example, illustrating the techniques explained on this page. Try clicking the download button at the bottom of the listing to experiment with it.

<!DOCTYPE html>
<html>
  <head>
  <title>Element Geometry Test</title>
  <meta charset="utf-8">

  <style type="text/css">
  DIV {
    margin: 8px 0px;
    padding: 8px 50px;
    width: 200px;
    height: 52px;
    overflow: hidden;
  }
  DIV P {
    margin: 0px;
    font-size: 12px;
    text-align: center;
    background: white;
  }
  DIV#red {
    background: red;
  }
  DIV#green {
    margin-left: 50px;
    background: green;
  }
  DIV#blue {
    margin-left: 50px;
    border-left: 50px solid #000040;
    background: blue;
  }
  SPAN {
    border: 1px solid red;
    padding: 1px 1ex;
    background: #E0E0E0;
    cursor: pointer;
  }
  </style>

  <script type="text/javascript">
  names = [ "red", "green", "blue" ];
  function measure() {
      for (var j in names) {
          var div = document.getElementById(names[j]);
          var p = div.getElementsByTagName("p")[0];
          var style = window.getComputedStyle(p, null);
          p.textContent = style.width
      }
  }
  function set_inner_width() {
      var width = this.textContent;
      for (var j in names) {
          document.getElementById(names[j]).style.width = width;
      }
      measure();
  }
  function set_outer_width() {
      var target = parseFloat(this.textContent);
      for (var j in names) {
	  var div = document.getElementById(names[j]);
	  var style = window.getComputedStyle(div, null);
	  var lengths = [ "margin-left", "border-left-width",
			  "padding-left", "padding-right" ];
	  var sum = 0;
	  for (var i in lengths) {
	      sum += parseFloat(style.getPropertyValue(lengths[i]));
	  }
	  div.style.width = (target-sum)+"px";
      }
      measure();
  }
  function init() {
      spans = document.getElementsByClassName("button1");
      for (var i in spans) spans[i].onclick = set_inner_width;
      spans = document.getElementsByClassName("button2");
      for (var i in spans) spans[i].onclick = set_outer_width;
      measure();
  }
  </script>
</head>
<body onload="init()">
  <img src="https://m.seehuhn.de/cssgeom/scale.png">
  <div id="red"><img src="https://m.seehuhn.de/cssgeom/scale.png"><p></div>
  <div id="green"><img src="https://m.seehuhn.de/cssgeom/scale.png"><p></div>
  <div id="blue"><img src="https://m.seehuhn.de/cssgeom/scale.png"><p></div>

  <hr>

  <p>Set inner width to:
  <span class="button1">300px</span>,
  <span class="button1">400px</span>,
  <span class="button1">500px</span>
  <p>Set outer width to:
  <span class="button2">300px</span>,
  <span class="button2">400px</span>,
  <span class="button2">500px</span>
</body>
</html>

[download]

References

Copyright © 2011, Jochen Voss. All content on this website (including text, pictures, and any other original works), unless otherwise noted, is licensed under a Creative Commons Attribution-Share Alike 3.0 License.