4
\$\begingroup\$

The Javascript libraries have pretty complicated functions to calculate an element's offset on the page. I wrote the following function that works in all the places I need it, and I've tested a few edge cases as well. It adds the element's offsetTop to its parent's offsetTop all the way up the DOM to the document. Can someone give me an example of where this wouldn't work?

This demo shows its results compared to jQuery's offset().top function.

Demo: http://jsfiddle.net/ThinkingStiff/5aGqM/

window.Object.defineProperty( Element.prototype, 'documentOffsetTop', {
    get: function () { 
        return this.offsetTop + ( this.offsetParent ? this.offsetParent.documentOffsetTop : 0 );
    }
} );

UPDATE:
I was looking for places where traversing up the DOM and adding the offset doesn't work in current browsers. As @Akkuma pointed out, Object.defineProperty doesn't work in earlier IEs.

\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

For starters, this doesn't work in IE7 or IE8. I'm assuming you knew that, although you never mentioned compatibility if any you were aiming for.

I rewrote what you made, to work in IE7 & IE8, so you can see where it fails. It is available at http://jsfiddle.net/Akkuma/Xem3B/

You'll find the following not working correctly in IE8 compared to the latest Chrome Dev 18 static, static (static wrapped), fixed/absolute (side), absolute/relative/static (absolute/relative wrapped), relative, and fixed/absolute (bottom).

In jQuery they do several different compatibility checks for whether a browser adds the border, for relative/static/fixed positioning, whether the browser subtracts the borders for overflows that are something other than visible. It appears modern browsers should support your approach just fine.

Your code appears to work fine in IE9, so if you aren't supporting IE8 & 7 your code should be good to go. However, if you take a look at jQuery's code you'll find they do not have to recursively traverse up the tree to calculate the offset in modern browsers that support getBoundingClientRect. The trade off is obviously one of simplicity (your own code) vs performance. I haven't verified which is faster, but I would expect jQuery's approach to keep getting faster the deeper the element is in the tree compared to your documentOffsetTop.

Update: If you haven't seen it, here is an older explanation from John Resig on it and what additional things they had to do (note this is from 2008, so the links are broken and I'm sure they may have modified it more) http://ejohn.org/blog/getboundingclientrect-is-awesome/. Additionally, here is the Mozilla documentation detailing how to properly use it cross-browser.

\$\endgroup\$
1
  • \$\begingroup\$ Ooooh, getBoundingClientRect. I like. I was less concerned with the wrapper (window.Object.defineProperty which I guess is the IE problem, but I only target the latest browsers anyway), and more concerned with whether traversing up the DOM works in all cases. It looks like getBoundingClientRect is preferred way. Thanks! \$\endgroup\$ Commented Jan 19, 2012 at 10:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.