Last active
May 17, 2022 13:11
-
-
Save enwin/6029193e5c7e4a8b4c2bcb9345e678c0 to your computer and use it in GitHub Desktop.
Detect and change the scroll position when a focused element is under a sticky element
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
// sticky element | |
var stickyHeader = document.querySelector( '.intro-banner' ); | |
function handleFocus( e ){ | |
// don't try to change the scroll if the focused element is in the sticky element | |
if( stickyHeader.contains( e.target )){ | |
return; | |
} | |
// quick & dirty client height on each focus | |
// get the sticky element's height (can be done on mediaquery change instead of each time) | |
var headerHeight = stickyHeader.clientHeight; | |
// get the screen position of the focused element | |
var focusTop = e.target.getBoundingClientRect().top; | |
// get the current scroll | |
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; | |
// scroll when the focused element is under the sticky element | |
if( focusTop < headerHeight ){ | |
document.documentElement.scrollTop = document.body.scrollTop = scrollTop - headerHeight; | |
} | |
} | |
document.body.addEventListener( 'focus', handleFocus, true ); |
Thanks for the feedback!
I simplified the gist because getBoundingClientRect()
returns positions based on the viewport, not the document. We can directly compare the .top
with the height of the sticky bar. We still need scrollTop
but only to place the scroll at the desired position.
As for the cross-browser compatibility. Webkit/Blink based browser will never trigger the repositioning since their focus algorithm seems to always put the focused element at the center of the screen (when there's enough space around).
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi there!
In my current project I needed to tweak this a bit:
offsetTop
isn't reliable enough because of (too) many absolute positions.So to get
focustTop
I usede.target.getBoundingClientRect().top + document.documentElement.scrollTop
and it's fine, now.It also decreases condition complexity:
focusTop <= (scrollTop + headerHeight)
seems sufficient.I didn't test this cross-browser for now, but I'll get back if I come across any trouble :)