DOM Element Dimensions and CSS Transforms

In a recent issue of my newsletter, I briefly discussed many (if not all?) of the different ways you can retrieve a DOM element’s dimensions via JavaScript.

These include:

  • Using getBoundingClientRect()‘s width and height properties
  • Via offsetWidth and offsetHeight
  • Using window.getComputedStyle()
  • By means of the document.styleSheets object
  • Using scrollWidth and scrollHeight

As you probably know, these features don’t work in the same way, so they don’t give you identical results. You can see the differences in the width and height values by viewing the following demo:

See the Pen
Different Ways to Get Width/Height Values with DOM Scripting
by Louis Lazaris (@impressivewebs)
on CodePen.

Notice the difference in values. The original dimensions of the box as defined in the CSS are 205.3px x 198.8px. I chose fractional values intentionally and I set box-sizing to border-box. The only DOM technique that gets the original dimensions is (of course) the one that accesses the stylesheet directly (document.styleSheets), a feature of the CSS Object Model, which makes sense. The other values are either much more precise or less precise. Feel free to fiddle around with the CSS to see how the results differ.

When researching this, however, I noticed the following note in an article on MDN on this subject:

In case of transforms, the offsetWidth and offsetHeight returns the element’s layout width and height, while getBoundingClientRect() returns the rendering width and height.

So that’s pretty interesting! Let’s put that to the test. In the demo below I’ve included four different boxes, each with a CSS transform applied to it (scale, skew, translate, and rotate).

There are two buttons on the page, one to display the dimensions of the four boxes via getBoundingClientRect() and the other to get the dimensions via offsetWidth and offsetHeight.

See the Pen
Dimensions of Elements with Transforms vs. Elements without Transforms
by Louis Lazaris (@impressivewebs)
on CodePen.

As you can see, using offsetWidth and offsetHeight the values are the same (the original dimensions). But with getBoundingClientRect() we get what’s actually rendered on the page after the transforms are applied. And as you probably noticed, the translate transform doesn’t affect the dimensions because translate just moves the element and doesn’t affect its shape.

If you’re curious how the dimensions of a non-rectangular shape are determined, the calculation is based on an imaginary box that’s created based on the furthest the element reaches while it’s in its transformed state. The following graphic demonstrates this:

When an element is transformed, its dimensions are based on an imaginary box
When an element is transformed, its dimensions are based on an imaginary box

And in case you’re wondering, the same basic principle applies when using 3D transforms, as shown in the following demo:

See the Pen
Dimensions of Elements with 3D Transforms Applied
by Louis Lazaris (@impressivewebs)
on CodePen.

Again, the dimensions (which are originally 200 x 200) are different for the transformed element when accessed via getBoundingClientRect().

Something to keep in mind if you’re grabbing width and height values of an element in the DOM that might be affected by a CSS transform.

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).