making bbPress (and WordPress) work better!

How to get an element’s TRUE position in javascript, including borders in Firefox

I’ve seen a bunch of scripts around the web to get an element’s (aka object) actual/absolute position on a page in javascript. Virtually all of them are wrong, for one very good reason – if you have borders on an element in ANY version of firefox, the position will be off by the border width.

I haven’t seen any script attempt to deal with borders.

This is because Firefox uses a broken “inner” model, regardless if you are in standards vs quirks mode, that was based on trying to mimic IE6 – the only other game in town when Firefox was evolved. But ironically, even IE has moved on to including borders since version 7/8 while Firefox remains the same from version 1 through 5. Good for backwards compatibility I guess but a headache for web developers.

So in plain English, in Firefox, margins count towards offsetLeft/offsetTop but NOT borders! It’s the only “html5” browser in existence right now that doesn’t include borders.

See these bug reports from SEVEN years ago, still unfixed:

Ignore where people claim their solution works – if it doesn’t include border calculations, it doesn’t work, they are misguided.

I used to have a very short and sweet function to grab an object’s true position on the page. (do not use this one)

function XY(o) {var z=o,x=z.offsetLeft||0,y=z.offsetTop||0; while(z=z.offsetParent) {x+=z.offsetLeft||0; y+=z.offsetTop||0;} return {x:o.X=x,y:o.Y=y};}

(it returns an object with .X .Y added (left and top) but also appends them to the original object for convenience)

However do not use the above script, it’s incomplete. Not only does it not properly deal with scrolled objects (div, iframe, etc.) it does not handle borders in firefox.

Sadly there is no fast & clean way to get border width in firefox, you have to use computedstyles from the best I can figure out, which must be relatively slow because of how it traverses stylesheets (if you know a faster way, please let me know).

So this (unfortunately larger) function I’ve come up with does finally produce identical results across Chrome, Firefox and IE8

function XY(o) {
var z=o, x=0,y=0, c; 
while(z && !isNaN(z.offsetLeft) && !isNaN(z.offsetTop)) {        
c = isNaN(window.globalStorage)?0:window.getComputedStyle(z,null); 
x += z.offsetLeft-z.scrollLeft+(c?parseInt(c.getPropertyValue('border-left-width'),10):0);
y += z.offsetTop-z.scrollTop+(c?parseInt(c.getPropertyValue('border-top-width'),10):0);
z = z.offsetParent;
return {x:o.X=x,y:o.Y=y};

But even though it’s larger, it’s still far better than turning to an 80k library like jquery. Note my use of “window.globalStorage” which is a trustworthy way of detecting anything based on the real gecko engine (since FF 2+) while ignoring all other browsers. No user-agent sniffing needed. Can’t use the navigator property – it’s useless because Chrome will also return “Gecko”.

3 responses

  1. This does not seem to work see

    June 17, 2015 at 12:03 pm

    • Sorry, works only in Firefox, not IE or Chome

      June 17, 2015 at 12:06 pm

  2. This seems to be the solution

    function getPosition(element) {
    var isNotFirefox = navigator.userAgent.toLowerCase().indexOf(‘firefox’) == -1;
    var xPosition = 0;
    var yPosition = 0;
    while(element) {
    xPosition += (element.offsetLeft – element.scrollLeft);
    yPosition += (element.offsetTop – element.scrollTop);
    if (isNotFirefox) {
    xPosition += element.clientLeft;
    yPosition += element.clientTop;
    element = element.offsetParent;
    return { x: xPosition, y: yPosition };

    June 17, 2015 at 4:40 pm

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s