I'm building a blog with a system to see how deep in an article the visitor is currently in, the result is in percentage.
To simplify some elements, I'm tracking the bottom border of the browser and comparing it to the article's actual position. The page itself is composed of a banner with some items inside (title, metadata, etc), then the article itself is displayed under it, but the banner's height is 60vh. The article has no set height, and no overflow: scroll
property.
This is how I'm currently doing it:
const getScrollPercent = () => {
const prose = document.querySelector<HTMLDivElement>('.prose')
if (prose) {
// closest way I got the actual div's top side)
const proseTop = prose.getBoundingClientRect().top document.documentElement.scrollTop
const proseBottom = proseTop prose.offsetHeight
const browserBottom = window.scrollY window.innerHeight
if (browserBottom < proseTop) {
return 0
} else if (browserBottom > proseTop && browserBottom < proseBottom) {
return (browserBottom / proseBottom) * 100
} else {
return 100
}
} else {
return 0
}
}
However, the behavior is a bit off: As long as I don't have the .prose
div in my viewport, it displays 0 percent, which is completely ok. However, at the first pixel, the percentage jumps to ~24%, and then it finishes smoothly at 100% once reaching the div's bottom.
I don't really know if it's my way of calculing the div's height that's not good, or how I calculate the progressing percentage.
Edit: Html structure
(It's a Nuxt/VueJS context)
<nav>
<!-- Contains some links-->
</nav>
<main>
<header>
<h1>Some article title with a banner in background</h1>
<div >
<!-- Some meta infos (tags, creation date, etc) -->
</div>
</header>
<div >
<span >
{{ getScrollPercent }}%
</span>
</div>
<article>
<!-- lots of <p> and <h2> to <h6> tags, about 2200px high) !-->
</article>
</main>
CodePudding user response:
Dividing by proseBottom is not the right way to do this. If proseTop is 5000, height is 200, proseBottom is going to be 5200. So even when browser bottom is at 5000, you are going to be at 5000/5200 percent, which isn't what you want (right?)
I think what you want is
(proseTop - browserBottom) / proseHeight * 100;
This is how you calculate the percentage of the prose field that is off screen below
CodePudding user response:
You need to get the reference of your div
node first.
in react most likely use useRef
const yourDivRef = useRef()
//then in your actual div
<div ref={yourDivRef}/>
then you could calculate ur position with code below
const node = yourDivRef.current
const offsetHeight = node.scrollHeight // this is about how height your ref div is
const innerHeight = node.clientHeight // this is how height your browser window is
const scrollTop = node.scrollTop // this is where you scroll position at
for example: if you want to get if you scroll reach the bottom you do
// check if scroll reach within 5px to the bottom
const hasReachedBottom = offsetHeight - (innerHeight scrollTop) <= 5
so as your asked:
(innerHeight scrollTop) / offsetHeight
should be the percentage
of position where you at in your div
Also don't forget to init the scroll Event listener.
useEffect(() => {
// handleScroll should be the place you do all the math.
listenTarget.addEventListener('scroll', handleScroll)
return () => listenTarget.removeEventListener('scroll', handleScroll)
}, [node])
I hope you find this is answer your question.