For some reason, there is no standard API to get the pixel coordinates of a DOM element relative to the upper-left corner of the document. APIs only exist to get coordinates relative to the offset parent. Problem is, it's very important to get those coordinates for applications such as drag and drop, or whenever you need to compare coordinates of elements that may be in completely different parts of the document.
In Microsoft Ajax, we implemented such a function (Sys.UI.DomElement.getLocation) but it proved to be one of the most difficult problems we had to solve. Not so surprisingly, every single browser has its own coordinate quirks that make it almost impossible to get the right results with just capability detection. This is one of the very rare cases where we reluctantly had to use browser sniffing and implement a completely different version of the function for each browser.
We also had to implement a pretty complex test suite to verify our algorithms for thousands of combinations of block or inline elements, offsets, scroll positions, frame containment, borders, etc., and run those on each browser that we support. The test suite in itself is quite interesting: it renders an element with the constraints to test, gets its coordinates from the API, creates a top-level semi-transparent element that is absolutely positioned and check that both overlap exactly to pixel precision. To do so, it takes a screen shot and analyses the image to find the rectangles and check their color.
The simplest runtime implementation is the IE one, thanks to a little-known API that does almost exactly what we want: getBoundingClientRect. Almost exactly as we quickly discovered it has a weird 2-pixel offset except on IE6 if the HTML element has a border (which is a "feature" that was removed in IE7 and which we chose not to support). It also doesn't include the document's scroll position. Finally, if the element is in a frame, the frame border should be subtracted. This actually was the cause for a bug that we unfortunately discovered after we shipped 1.0 but which is now fixed in ASP.NET 3.5 as the parent frame may not be in the same domain, in which case attempting to get its frame border will result in an access denied error. So you need to do this in a try-catch and just accept the bad offset in that fringe scenario.
In all other browsers, you currently need to recurse through the offset parents of the element and sum the offset coordinates.
In Safari 2, though, the body's offset gets counted twice for absolutely-positioned elements that are direct children of body. Something you don't just guess, you need the thousands of test cases I mentioned earlier to discover something like that...
In both Safari and Firefox, you must subtract to the coordinates the scroll positions of all parent nodes (and not the offset parents like before). Well, except if the element is absolutely positioned (this last restriction doesn't apply to Opera). Or if the parent is the body or html element. Confused yet? Wait, there's more.
In Firefox, non-absolutely positioned elements that are direct children of body get the body offset counted twice.
In both IE and Firefox (but you don't care for IE as it has getBoundingClientRect), the border of a table gets counted in both the border of the table and in the td's offset.
Finally, on Opera, there are scroll values on elements that are not scrolled so you need to explicitly check for the overflow mode before you subtract scroll positions. Opera also includes the scrolling into the offsets, except for positioned contents.
The worst part in all this is that we don't even know for sure that we nailed it, and we know that future browsers will require adjustments.
Speaking of which... Firefox 3 will implement getBoundingClientRect. I haven't tried their implementation yet and checked whether it has the IE quirks, but it should be a lot simpler than what we have to work around today to do the same thing and we'll definitely have to rely on less undocumented quirks. By the way, if you were thinking of using the undocumented getBoxObjectFor, forget it, it was designed for XUL elements and will probably get removed from non-XUL elements in future versions.
There is a bug open against WebKit to get that in Safari but it's currently without an owner. Here's to hoping this gets into the next version. Vote for it.