How might I enable automatic scrolling to the top of an element only when the user initiates a downward vertical scroll event over an element above it? I'd like to do this so that a scroll action at the top of the page initiates a smooth glide and snap to the next important element for UI/UX purposes. I am using Svelte.
<script>
import Card from './Card.svelte';
const cards = ["card1", "card2", "card3", "card4"]
let y = 0;
let lastY = 0;
let theater;
let upperContainer;
const scrollToTheater = (y) => {
let dy = lastY - y;
lastY = y;
if (dy < -10) {
document.body.parentNode.scrollTo({
top: theater.offsetTop,
left: 0,
behavior: 'smooth'
})
}
}
$: scrollToTheater(y);
</script>
<svelte:window bind:scrollY={y} />
<main>
<header>
<h1>Hello World!</h1>
</header>
<div id="upper-container" bind:this="{upperContainer}">
<h2>Capture scroll over this area only</h2>
</div>
<div class="theater" bind:this="{theater}">
{#each cards as card}
<Card {card} />
{/each}
</div>
<footer>
Footer
</footer>
</main>
<style>
header {
width: 100%;
height: 40px;
padding:10px 20px 0 0;
}
#upper-container {
width: 100%;
height: 50vw;
margin: 30px 0;
background-color: rebeccapurple;
}
.theater {
background-color: black;
overflow: hidden;
}
</style>
Here is a REPL. In the REPL, you can see that while the effect works when scrolling over the purple div, it interferes with scrolling from the area below.
I have tried writing the scroll event listener in alternative ways by removing:
<svelte:window bind:scrollY={y} />
and adding:
<div id="upper-container" bind:this="{upperContainer}" on:scroll={() => {alert("scrolled")}}>
or:
onMount(() => {
const upper_container = document.getElementById("upper-container");
upper_container.addEventListener("scroll", () => alert("scroll"))
});
with no results (see the commented out blocks in the REPL). These events function as expected if I replace "scroll" with "click". I also tried using getBoundingClientRect().bottom
to test the position of the cursor relative to the element, but when I place upperContainer.getBoundingClientRect().bottom
in the scrollToTheater
function block, upperContainer
is undefined
.
The scroll event will only fire if a scroll actually happens. In your example you don't have enough content inside the box you're looking for the scroll on to make that happen.
Here's your REPL with content added in the box using the onMount technique and binding to the element.
And here's the REPL with the on:scroll
event handler on the container no binding needed, both work fine.
If however what you're trying to track is when the mousewheel is scrolled over the container even when there isn't enough content inside the container to trigger the scroll then you'll need to use the on:wheel
handler instead as shown in this version of the REPL, you may or may not want to preventDefault when doing this and it definitely does not account for mobile users but this also works.