Reputation: 435
Out webpage has a vertical scroll until it reaches the bottom, at that point we want it to start scrolling horizontally.
It should also work in reverse, so when the user reaches the end of the horizontal scroll, the user can go back using the mouse wheel to the top, following the same path.
To make it clearer, the webpage wrapper is like an "L". It's the same movement as this website as it gets to: "We've taken on at least 300%".
I've seen useful advice about horizontal scroll, but i can't implement it to the vertical one.
Upvotes: 2
Views: 3304
Reputation: 26567
Under normal circumstances, I'd give the normal shpeal about "what have you tried, show stuff", which you should definitely follow on Stack Overflow: How do I ask a good question?
That said, this was a particularly interesting problem, so I decided to take a stab.
I recommend checking out the example in full page mode after hitting "Run code snippet":
const root = document.getElementById('root');
const content = document.getElementById('content');
root.addEventListener('wheel', e => {
e.preventDefault();
e.stopPropagation();
const delta = e.deltaY;
const maxScrollY = content.offsetHeight - root.offsetHeight;
const maxScrollX = content.offsetWidth - root.offsetWidth;
let scrollY = root.scrollTop;
let scrollX = root.scrollLeft;
if (scrollX > 0) {
scrollX += delta;
if (scrollX < 0) {
scrollY -= scrollX;
scrollX = 0;
}
} else {
scrollY += delta;
const overflow = scrollY - maxScrollY;
if (overflow > 0) {
scrollX += overflow;
scrollY = maxScrollY;
} else {
scrollX = 0;
}
}
root.scrollTo(scrollX, scrollY);
});
#root {
width: 500px;
height: 500px;
overflow: hidden;
}
#content {
width: 5000px;
height: 1000px;
}
/* This is just to have something in content so we can see it moving */
#content {
border: 50px solid #F00;
background-image:
linear-gradient(0deg, rgba(0, 0, 255, .5) 0%, rgba(0, 0, 255, .5) 50%, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0) 100%),
linear-gradient(90deg, #000 0%, #000 50%, #FFF 50%, #FFF 100%);
background-repeat: repeat;
background-size: 1% 5%;
}
<div id="root">
<div id="content"></div>
</div>
This solution requires that you have two elements, an outer "root" and an inner "content". The window should be to be the "root" element (just switch it to const root = window;
).
Basically, we then hijack the wheel
event on the root element. Any time it happens, we need to add it to either scrollLeft
or scrollTop
.
If our scrollX
/scrollLeft
is 0
, then we'll add it to scrollY
/scrollTop
. We then check for any extra scroll when we hit the bottom. If we have any, we'll add that to scrollX
.
If our scrollX
is not zero, then we'll just add any scroll directly to it. If it becomes less than zero, we'll set it to zero and give the extra to scrollY
so it can go back up.
Since deltaY
will be negative or positive, we don't have to do any special math to be able to deal with it.
For the CSS, the only important bit is that the root
element has overflow
hidden. If you are using window, set html
to overflow: hidden
. The "content" then needs to have some width. You don't necessarily have to explicitly set it, because your content will give it a size.
Upvotes: 1