I have this code for vehicle to horizontal and back to vertical scrolling, however it only works on mouse wheel scroll. I also need it to respond accordingly to mobile touch, scrollbars, page up/down, and the keyboard arrow keys. Below is my code:
(function(){ init(); var g_containerInViewport; function init(){ setStickyContainersSize(); bindEvents(); } function bindEvents(){ window.addEventListener("wheel", wheelHandler); //do not work window.addEventListener("touchstart", wheelHandler); window.addEventListener("touchmove", wheelHandler); window.addEventListener("touchend", wheelHandler); window.addEventListener("touchcancel", wheelHandler); } function setStickyContainersSize(){ document.querySelectorAll('.sticky-container').forEach(function(container){ const stikyContainerHeight = (container.querySelector('main').offsetWidth + window.innerHeight); container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px'); }); } function isElementInViewport (el) { const rect = el.getBoundingClientRect(); return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight; } function wheelHandler(evt){ const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container){ return isElementInViewport(container); })[0]; if(!containerInViewPort){ return; } var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop; var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop; let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom; if(g_canScrollHorizontally){ containerInViewPort.querySelector('main').scrollLeft += evt.deltaY; } } })();
html, body { margin: 0; font-family: sans-serif; } .vertical-section{ height: 100vh; display: flex; align-items: center; justify-content: center; } main { overflow-x: hidden; display: flex; position: sticky; top:0; } h1 { margin: 0; padding: 0; } section { min-width: 50vw; min-height: 100vh; display: flex; justify-content: center; align-items: center; font-size: 4ch; } section:nth-child(even) { background-color: teal; color: white; }
<div class="vertical-section"> scrolling is vertical </div> <div class="sticky-container"> <main> <section> <h1>scrolling</h1> </section> <section> <h1>is</h1> </section> <section> <h1>now</h1> </section> <section> <h1>horizontal</h1> </section> </main> </div> <div class="vertical-section"> scrolling is vertical again </div> <div class="sticky-container"> <main> <section> <h1>scrolling</h1> </section> <section> <h1>is</h1> </section> <section> <h1>now</h1> </section> <section> <h1>horizontal</h1> </section> </main> </div>
How can I make this work for mobile touch, scroll bar, arrow keys, and page up/down?
Thanks
Advertisement
Answer
My solution was to use the scroll event, it works on all devices:
let lastKnownScrollPosition = 0; let deltaY = 0; window.addEventListener("scroll", wheelHandler); document.querySelectorAll('.sticky-container').forEach(function(container) { const stikyContainerHeight = (container.querySelector('main').offsetWidth + window.innerHeight); container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px'); }); function isElementInViewport(el) { const rect = el.getBoundingClientRect(); return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight; } function wheelHandler(event) { deltaY = window.scrollY - lastKnownScrollPosition; lastKnownScrollPosition = window.scrollY; console.log('deltaY', deltaY); const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container) { return isElementInViewport(container); })[0]; if (!containerInViewPort) { return; } var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop; var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop; let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom; if (g_canScrollHorizontally) { containerInViewPort.querySelector('main').scrollLeft += deltaY; } }