getBoundingClientRect is Awesome

getBoundingClientRect is a method, first introduced by Internet Explorer 5 (and now included in Firefox 3), which provides the top, right, bottom, and left offset coordinates of an element. After PPK mentioned this method in a recent post of his, poo-poo-ing its applicability, I thought I’d take some time to show how useful it can be. What makes this method so especially handy is that the alternative means of computing an element’s offset position is so horribly slow and buggy that it borders on the comical.

The general purpose of this method, or of similar implementations, is to allow the user to get the visual top/left position of an element (such that if they absolutely position an element from the document it would be on top of the desired element – making things like tooltips possible, to name a single application). This means that you have to take into account a huge number of quirks. In no particular order here are some choice bugs which make this very difficult:

Handling table border offsets.

Fixed positioned elements.

Scroll offsets within another element.

Borders of overflowed parent elements.

Miscalculation of absolutely positioned elements.

For example, looking at jQuery’s implementation of .offset() (which provides the top/left offset of an element) we can see a number of these quirks worked around. A phenomenal amount of work has gone into the method, by the excellent Brandon Aaron, in order to “get it right” in a cross-browser manner. Check out the extensive suite of tests that are backing it up, as well.

This is where getBoundingClientRect comes into play. For a visual comparison look at the green boxes (representing the getBoundClientRect-based implementation) versus the red boxes (representing the normal cross-browser implementation).

The reason why the getBoundingClientRect implementation is more than 1 line is due to two facts:

It doesn’t include the document scroll offset (which is a simple addition).

In comparison to the default technique, however, this is a veritable walk-in-the-park.

Now, not only, is this method simpler to use it’s also insanely faster. Stupifyingly so. Considering that you no longer have to perform all sorts of hacks, or walk the tree to rectify miscalculations, the result is quite impressive.

View the following jQuery UI drag-and-drop sorting demo page in Firefox 2 (drag the items in the grid, at the bottom) and then view it in Firefox 3, doing this same:

I might have to spend some time getting my thesis code working on Firefox 3; this method alone would make it run considerably faster! I have no doubts about its applicability, at least as far as making my own life easier. :)

This is a major and much-needed improvement for Firefox. Thank you for blogging about it.

I work on a web service that uses a javascript-API to semantically analyse text and provides information about it through a popup. Positioning the popup on the page is a cross-browser mess. Solving this problem really matters for web-services that do content display through remote APIs.

I wonder why not use Dom.Element.getBoxObjectFor() to get the dimension and position of an element on Firefox? It had been available since Firefox 1 and I found it very useful just like getBoundingClientRect();

I tested document.documentElement.clientLeft and document.documentElement.clientTop in IE6/win and found in both modes (standard and quirks), they can reflect the css settings ‘html { border:0;}’. The test result is different from the comments in offset.js.

In IE6/win quirks mode, document.documentElement.clientLeft and document.documentElement.clientTop are allways 0 no matter what value is used to set html element’s border. On the contrary, in IE6/win standard mode, clientLeft and clientTop properties are always equal to the html’s border width. So in offset.js,

add(-doc.documentElement.clientLeft, -doc.documentElement.clientTop)

only affects IE6/win standard mode, which makes the element’s left and top values small.

Actually, the element’s left and top values are already correct before this adjustment. Those values are relative to the origin of document. But after this adjustment in IE6/win standard mode, those values are relative to the inner edge of html element.

Unfortunately i found out, that getBoundingClientRect does not work, if there is an element with position == “relative” or “absolute” between and the element of question.

The body’s margin is then not added. Event wors when you have a with position:relative, or another relative positioned element with a margin.
This method seems too buggy to me. I tested it on IE 7 / WinXP.

Ok, i must admit, it was my fault in testing. I positioned an “pointer” element, which was in the body, to the element of question. And of course, if the body is relative, the absolute position of the “pointer” element, refers to the body. Sorry…

Comments are closed.
Comments are automatically turned off two weeks after the original post. If you have a question
concerning the content of this post, please feel free to contact me.