Last active
July 18, 2022 11:03
-
-
Save jlong/eff01958791d3e0bf10c to your computer and use it in GitHub Desktop.
Get the offset of an element relative to the viewport and take scrolling and borders into account
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getViewportOffset(element) { | |
var node = element | |
, left = node.offsetLeft | |
, top = node.offsetTop | |
; | |
node = node.parentNode; | |
do { | |
var styles = getComputedStyle(node); | |
if (styles) { | |
var position = styles.getPropertyValue('position'); | |
left -= node.scrollLeft; | |
top -= node.scrollTop; | |
if (/relative|absolute|fixed/.test(position)) { | |
left += parseInt(styles.getPropertyValue('border-left-width'), 10); | |
top += parseInt(styles.getPropertyValue('border-top-width'), 10); | |
left += node.offsetLeft; | |
top += node.offsetTop; | |
} | |
node = position === 'fixed' ? null : node.parentNode; | |
} else { | |
node = node.parentNode; | |
} | |
} while (node); | |
return { left: left, top: top }; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
looks fine at first,
but sometimes it goes up the DOM-tree up too far (the
document
-object, [abovedocument.documentElement
]) which can not be used withgetComputedStyle
,that will throw an error of
Uncaught TypeError: Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
,The second thing I've discovered is that sometimes
scrollLeft
and/orscrollTop
areundefined
, which will turn your collectedleft
andtop
values toNaN
...The following is pretty much the code above, but with those, and several other fixes (plus, I too love 'comma-first' syntax :])
The code is overly explicit, and commented-in on several issues I've thought it is best to explain,
especially for myself in-case I would need to use it some time from now...