Update: I submitted this to MochiKit while building Snipshot, a web tool to edit pictures online.

I discovered that IE’s clientX and clientY measurements were sometimes a couple pixels out. It turns out this is because IE’s clientX and clientY measurements start from (2,2) in standards mode, and (0,0) in quirks mode.

IE stores this offset in its document.documentElement.clientLeft and document.documentElement.clientTop properties. This code should calculate the correct cursor position in all current browsers:

function getPosition(e) {
    e = e || window.event;
    var cursor = {x:0, y:0};
    if (e.pageX || e.pageY) {
        cursor.x = e.pageX;
        cursor.y = e.pageY;
    } 
    else {
        var de = document.documentElement;
        var b = document.body;
        cursor.x = e.clientX + 
            (de.scrollLeft || b.scrollLeft) - (de.clientLeft || 0);
        cursor.y = e.clientY + 
            (de.scrollTop || b.scrollTop) - (de.clientTop || 0);
    }
    return cursor;
}
 
JavaScript Positioning January 20, 2006

To find out exactly how browsers were interpreting offsetLeft and offsetTop, I built a test page that would tell me I added a 1px margin, 2px border, 4px padding, 8px position, 16px margin, and so on and then used bitwise AND to figure out which parts were being included in the total calculation. what parts of the style calculation were included.

It’s a mess. Firefox and Opera do the calculation in the same way, while Safari and IE each have unique interpretations. IE has the only obvious bug, where the top padding of an element is not included in one calculation, while the left padding is.

The only thing that appears to work consistently is finding an element’s absolute position on a page—as long as no elements have any borders, margins, or padding.

It is possible to get the browsers a little closer to the correct answer if you include the IE-specific clientTop and clientLeft properties. Here’s a test page to demonstrates this. In this case, Safari, IE, and Opera agree on the absolute x coordinate, IE still won’t include y padding, and Firefox is on its own.

I think this comment sums up the problem nicely:

“The problem to begin with, the origin of the problem is that MSDN does not define strictly, explicitly how offsetLeft/offsetTop should be computed in normal situations and in various other situations. Even offsetParent is not defined clearly: there is no precise spec. - formal rigorous spec - identifying how the offsetParent can be, should be determined. offsetLeft, offsetTop definitions are circularly dependent, self-inter-dependent to offsetParent definition.

Add to this quirks mode vs standards rendering mode, and other properties (padding, border, margin, box-sizing) which interfere or affect too calculations of offsetLeft, offsetTop or which may influence too the way offsetParent is to be defined and then you have a real mess, headache, impossible task.â€

 
JavaScript Events January 18, 2006

I’m trying to help out the MochiKit and Dojo projects by writing an event normalizer. I’m tired of writing or finding one-off functions to solve this problem, and want something that will return accurate cursor and element coordinates.

I built a test page to collect seven browsers’ interpretations of a set of event properties. The only event property I normalized was event.target, I left everything else alone. The proxy.* values are calculated based on some assumptions I had about how the browsers interpreted the target’s position (proxy.pos), the cursor position relative to the document (proxy.page), the cursor position relative to the target (proxy.targetOffset), and the cursor position relative to the target’s positioning context (proxy.contextOffset). I used Pixie (Mac) and ZoomPlusU (PC) to position the cursor on every test.

My code still needs some work.

Note that Firefox 1.5 (Gecko 2005-11-11) introduced an off-by-one bug to the event.layerX and event.layerY properties. It’s been fixed in the latest nightly builds.

Also note that IE’s clientX and clientY properties are off by two pixels. From MSDN: “In Microsoft Internet Explorer 5, the window's upper-left is at 2,2 (pixels) with respect to the true client.†The proxy.page.x/y and .targetOffset.x/y variables seem to be relatively consistent up until test point five, when I measure point (1,1) in the document's first absolutely positioned element.

A lot of libraries do something like:

event.layerX = event.layerX || event.offsetX

This is incorrect, layerX and offsetX are not equivalent.

Here is the test page. (Hold down the alt key and click on any part of the page to get a variable dump.) I did nine manual tests at different points in the document, starting from the top left corner of the document. I’ve included Pixie screenshots to show where I’m taking my sample.

There is still a lot of work to do, and I would really appreciate your feedback on what I’ve got so far. You can reach me at beau@hartshorne.ca.

One

one.png
Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id html html html html html html html
event.pageX 1 1 1 1 1 - 1
event.pageY 1 1 1 1 1 - 1
event.offsetX 1 1 - - - 1 1
event.offsetY 1 1 - - - 1 1
event.layerX 1 1 1 2 1 - -
event.layerY 1 1 1 2 1 - -
event.clientX 1 1 1 1 1 3 1
event.clientY 1 1 1 1 1 3 1
event.x 1 1 - - - 3 1
event.y 1 1 - - - 3 1
target.offsetLeft 0 0 0 0 0 0 0
target.offsetTop 0 0 0 0 0 0 0
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 0 0 0 0 0 - 0
window.pageYOffset 0 0 0 0 0 - 0
document. documentElement. scrollLeft 0 0 0 0 0 0 0
document. body.scrollLeft 0 0 0 0 0 0 0
document. documentElement. scrollTop 0 0 0 0 0 0 0
document. body.scrollTop 0 0 0 0 0 0 0
proxy.pos.x 0 0 0 0 0 0 0
proxy.pos.y 0 0 0 0 0 0 0
proxy.page.x 1 1 1 1 1 3 1
proxy.page.y 1 1 1 1 1 3 1
proxy.targetOffset.x 1 1 1 1 1 3 1
proxy.targetOffset.y 1 1 1 1 1 3 1
proxy.contextOffset.x 1 1 1 1 1 3 1
proxy.contextOffset.y 1 1 1 1 1 3 1

Two

two.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id body body body body body body body
event.pageX 11 11 11 11 11 - 11
event.pageY 11 11 11 11 11 - 11
event.offsetX 1 11 - - - -9 -19
event.offsetY 1 11 - - - -9 -19
event.layerX 11 11 11 12 11 - -
event.layerY 11 11 11 12 11 - -
event.clientX 11 11 11 11 11 13 11
event.clientY 11 11 11 11 11 13 11
event.x 11 11 - - - 13 11
event.y 11 11 - - - 13 11
target.offsetLeft 10 10 -10 -10 -10 10 10
target.offsetTop 10 10 -10 -10 -10 10 10
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 0 0 0 0 0 - 0
window.pageYOffset 0 0 0 0 0 - 0
document. documentElement. scrollLeft 0 0 0 0 0 0 0
document. body.scrollLeft 0 0 0 0 0 0 0
document. documentElement. scrollTop 0 0 0 0 0 0 0
document. body.scrollTop 0 0 0 0 0 0 0
proxy.pos.x 0 0 0 0 0 0 0
proxy.pos.y 0 0 0 0 0 0 0
proxy.page.x 11 11 11 11 11 13 11
proxy.page.y 11 11 11 11 11 13 11
proxy.targetOffset.x 11 11 11 11 11 13 11
proxy.targetOffset.y 11 11 11 11 11 13 11
proxy.contextOffset.x 21 21 1 1 1 23 21
proxy.contextOffset.y 21 21 1 1 1 23 21

Three

three.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id body body body body body body body
event.pageX 21 21 21 21 21 - 21
event.pageY 21 21 21 21 21 - 21
event.offsetX 11 21 - - - 1 -9
event.offsetY 11 21 - - - 1 -9
event.layerX 21 21 21 22 21 - -
event.layerY 21 21 21 22 21 - -
event.clientX 21 21 21 21 21 23 21
event.clientY 21 21 21 21 21 23 21
event.x 21 21 - - - 23 21
event.y 21 21 - - - 23 21
target.offsetLeft 10 10 -10 -10 -10 10 10
target.offsetTop 10 10 -10 -10 -10 10 10
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 0 0 0 0 0 - 0
window.pageYOffset 0 0 0 0 0 - 0
document. documentElement. scrollLeft 0 0 0 0 0 0 0
document. body.scrollLeft 0 0 0 0 0 0 0
document. documentElement. scrollTop 0 0 0 0 0 0 0
document. body.scrollTop 0 0 0 0 0 0 0
proxy.pos.x 0 0 0 0 0 0 0
proxy.pos.y 0 0 0 0 0 0 0
proxy.page.x 21 21 21 21 21 23 21
proxy.page.y 21 21 21 21 21 23 21
proxy.targetOffset.x 21 21 21 21 21 23 21
proxy.targetOffset.y 21 21 21 21 21 23 21
proxy.contextOffset.x 31 31 11 11 11 33 31
proxy.contextOffset.y 31 31 11 11 11 33 31

Four

four.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id one one one one one one one
event.pageX 1001 1001 1001 1001 1001 - 1001
event.pageY 1001 1001 1001 1001 1001 - 1001
event.offsetX 1 1001 - - - -9 -19
event.offsetY 1 1001 - - - -9 -19
event.layerX 1 1 1 2 1 - -
event.layerY 1 1 1 2 1 - -
event.clientX 1001 1001 576 576 576 551 801
event.clientY 1001 1001 336 333 333 256 361
event.x 1001 1001 - - - 551 801
event.y 1001 1001 - - - 256 361
target.offsetLeft 1000 1000 1000 1000 1000 1000 1000
target.offsetTop 1000 1000 1000 1000 1000 1000 1000
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 468 557 425 425 425 - 200
window.pageYOffset 736 863 665 668 668 - 640
document. documentElement. scrollLeft 0 0 425 425 425 452 200
document. body.scrollLeft 468 557 0 0 0 0 200
document. documentElement. scrollTop 0 0 665 668 668 747 640
document. body.scrollTop 736 863 0 0 0 0 640
proxy.pos.x 1000 1000 1000 1000 1000 1000 1000
proxy.pos.y 1000 1000 1000 1000 1000 1000 1000
proxy.page.x 1001 1001 1001 1001 1001 1003 1001
proxy.page.y 1001 1001 1001 1001 1001 1003 1001
proxy.targetOffset.x 1 1 1 1 1 3 1
proxy.targetOffset.y 1 1 1 1 1 3 1
proxy.contextOffset.x 1001 1001 1001 1001 1001 1003 1001
proxy.contextOffset.y 1001 1001 1001 1001 1001 1003 1001

Five

five.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id one one one one one one one
event.pageX 1011 1011 1011 1011 1011 - 1011
event.pageY 1011 1011 1011 1011 1011 - 1011
event.offsetX 11 1011 - - - 1 -9
event.offsetY 11 1011 - - - 1 -9
event.layerX 11 11 11 12 11 - -
event.layerY 11 11 11 12 11 - -
event.clientX 1011 1011 586 586 586 561 811
event.clientY 1011 1011 346 343 343 266 371
event.x 1011 1011 - - - 561 811
event.y 1011 1011 - - - 266 371
target.offsetLeft 1000 1000 1000 1000 1000 1000 1000
target.offsetTop 1000 1000 1000 1000 1000 1000 1000
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 468 557 425 425 425 - 200
window.pageYOffset 736 863 665 668 668 - 640
document. documentElement. scrollLeft 0 0 425 425 425 452 200
document. body.scrollLeft 468 557 0 0 0 0 200
document. documentElement. scrollTop 0 0 665 668 668 747 640
document. body.scrollTop 736 863 0 0 0 0 640
proxy.pos.x 1000 1000 1000 1000 1000 1000 1000
proxy.pos.y 1000 1000 1000 1000 1000 1000 1000
proxy.page.x 1011 1011 1011 1011 1011 1013 1011
proxy.page.y 1011 1011 1011 1011 1011 1013 1011
proxy.targetOffset.x 11 11 11 11 11 13 11
proxy.targetOffset.y 11 11 11 11 11 13 11
proxy.contextOffset.x 1011 1011 1011 1011 1011 1013 1011
proxy.contextOffset.y 1011 1011 1011 1011 1011 1013 1011

Six

six.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id two two two two two two two
event.pageX 1031 1031 1031 1031 1031 - 1031
event.pageY 1031 1031 1031 1031 1031 - 1031
event.offsetX 1 1031 - - - -9 -19
event.offsetY 1 1031 - - - -9 -19
event.layerX 31 31 31 32 31 - -
event.layerY 31 31 31 32 31 - -
event.clientX 1031 1031 606 606 606 581 831
event.clientY 1031 1031 366 363 363 276 391
event.x 1031 1031 - - - 581 831
event.y 1031 1031 - - - 276 391
target.offsetLeft 30 30 20 20 20 20 20
target.offsetTop 30 30 20 20 20 10 20
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 468 557 425 425 425 - 200
window.pageYOffset 736 863 665 668 668 - 640
document. documentElement. scrollLeft 0 0 425 425 425 452 200
document. body.scrollLeft 468 557 0 0 0 0 200
document. documentElement. scrollTop 0 0 665 668 668 747 640
document. body.scrollTop 736 863 0 0 0 0 640
proxy.pos.x 1030 1030 1020 1020 1020 1020 1020
proxy.pos.y 1030 1030 1020 1020 1020 1010 1020
proxy.page.x 1031 1031 1031 1031 1031 1033 1031
proxy.page.y 1031 1031 1031 1031 1031 1023 1031
proxy.targetOffset.x 1 1 11 11 11 13 11
proxy.targetOffset.y 1 1 11 11 11 13 11
proxy.contextOffset.x 31 31 31 31 31 33 31
proxy.contextOffset.y 31 31 31 31 31 23 31

Seven

seven.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id two two two two two two two
event.pageX 1041 1041 1041 1041 1041 - 1041
event.pageY 1041 1041 1041 1041 1041 - 1041
event.offsetX 11 1041 - - - 1 -9
event.offsetY 11 1041 - - - 1 -9
event.layerX 41 41 41 42 41 - -
event.layerY 41 41 41 42 41 - -
event.clientX 1041 1041 616 616 616 591 841
event.clientY 1041 1041 376 373 373 286 401
event.x 1041 1041 - - - 591 841
event.y 1041 1041 - - - 286 401
target.offsetLeft 30 30 20 20 20 20 20
target.offsetTop 30 30 20 20 20 10 20
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 468 557 425 425 425 - 200
window.pageYOffset 736 863 665 668 668 - 640
document. documentElement. scrollLeft 0 0 425 425 425 452 200
document. body.scrollLeft 468 557 0 0 0 0 200
document. documentElement. scrollTop 0 0 665 668 668 747 640
document. body.scrollTop 736 863 0 0 0 0 640
proxy.pos.x 1030 1030 1020 1020 1020 1020 1020
proxy.pos.y 1030 1030 1020 1020 1020 1010 1020
proxy.page.x 1041 1041 1041 1041 1041 1043 1041
proxy.page.y 1041 1041 1041 1041 1041 1033 1041
proxy.targetOffset.x 11 11 21 21 21 23 21
proxy.targetOffset.y 11 11 21 21 21 23 21
proxy.contextOffset.x 41 41 41 41 41 43 41
proxy.contextOffset.y 41 41 41 41 41 33 41

Eight

eight.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id three three three three three three three
event.pageX 1191 1191 1191 1191 1191 - 1191
event.pageY 1061 1061 1061 1061 1061 - 1061
event.offsetX 1 1191 - - - -9 -19
event.offsetY 1 1061 - - - -9 -19
event.layerX 191 191 191 192 191 - -
event.layerY 61 61 61 62 61 - -
event.clientX 1191 1191 766 766 766 731 991
event.clientY 1061 1061 396 393 393 306 421
event.x 1191 1191 - - - 731 991
event.y 1061 1061 - - - 306 421
target.offsetLeft 190 190 180 180 180 140 180
target.offsetTop 60 60 50 50 50 20 50
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 468 557 425 425 425 - 200
window.pageYOffset 736 863 665 668 668 - 640
document. documentElement. scrollLeft 0 0 425 425 425 452 200
document. body.scrollLeft 468 557 0 0 0 0 200
document. documentElement. scrollTop 0 0 665 668 668 747 640
document. body.scrollTop 736 863 0 0 0 0 640
proxy.pos.x 1190 1190 1180 1180 1180 1160 1180
proxy.pos.y 1060 1060 1050 1050 1050 1030 1050
proxy.page.x 1191 1191 1191 1191 1191 1183 1191
proxy.page.y 1061 1061 1061 1061 1061 1053 1061
proxy.targetOffset.x 1 1 11 11 11 23 11
proxy.targetOffset.y 1 1 11 11 11 23 11
proxy.contextOffset.x 191 191 191 191 191 163 191
proxy.contextOffset.y 61 61 61 61 61 43 61

Nine

nine.png
   Apple WebKit / 417.9 Safari / 417.8 Apple WebKit / 420+ Safari / 417.8 Gecko / 2005-09-15 Firefox / 1.0.7 Gecko / 2005-11-11 Firefox / 1.5 Gecko / 2006-01-17 Firefox / 1.6a1 MSIE / 6.0. 2900. 2180 Opera 8.5 / Build 2173
event.target.id three three three three three three three
event.pageX 1201 1201 1201 1201 1201 - 1201
event.pageY 1071 1071 1071 1071 1071 - 1071
event.offsetX 11 1201 - - - 1 -9
event.offsetY 11 1071 - - - 1 -9
event.layerX 201 201 201 202 201 - -
event.layerY 71 71 71 72 71 - -
event.clientX 1201 1201 776 776 776 741 1001
event.clientY 1071 1071 406 403 403 316 431
event.x 1201 1201 - - - 741 1001
event.y 1071 1071 - - - 316 431
target.offsetLeft 190 190 180 180 180 140 180
target.offsetTop 60 60 50 50 50 20 50
window.innerHeight 527 417 620 617 617 - 617
window.innerWidth 802 713 860 860 860 - 1085
window.pageXOffset 468 557 425 425 425 - 200
window.pageYOffset 736 863 665 668 668 - 640
document. documentElement. scrollLeft 0 0 425 425 425 452 200
document. body.scrollLeft 468 557 0 0 0 0 200
document. documentElement. scrollTop 0 0 665 668 668 747 640
document. body.scrollTop 736 863 0 0 0 0 640
proxy.pos.x 1190 1190 1180 1180 1180 1160 1180
proxy.pos.y 1060 1060 1050 1050 1050 1030 1050
proxy.page.x 1201 1201 1201 1201 1201 1193 1201
proxy.page.y 1071 1071 1071 1071 1071 1063 1071
proxy.targetOffset.x 11 11 21 21 21 33 21
proxy.targetOffset.y 11 11 21 21 21 33 21
proxy.contextOffset.x 201 201 201 201 201 173 201
proxy.contextOffset.y 71 71 71 71 71 53 71
 

» Older Entries


You are viewing a mobilized version of this site...
View original page here

Mobilized by Mowser Mowser