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()
‘swidth
andheight
properties - Via
offsetWidth
andoffsetHeight
- Using
window.getComputedStyle()
- By means of the
document.styleSheets
object - Using
scrollWidth
andscrollHeight
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
andoffsetHeight
returns the element’s layout width and height, whilegetBoundingClientRect()
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:
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.
Great article. That’s exactly why one should use getBoundingClientRect() when doing calculations based on scroll / resize ( like enter/exit viewport etc ) to get dimensions of what you see on screen.
Without an imaginary box, getClientBoundingrect wouldn’t justify its argument. I hope dev tools will have a way to draw the box and make it easier to understand. I wonder where the other options are usable i-e document.styleSheet, scrollWidth/height and clientWidth/height.