Reputation: 2161
My website consists of several sections, with each section occupying an entire page. As the user tries to scrolls down, what I'm trying to accomplish is:
Example websites:
scroll-snap-align
: This method only snaps the scrolling after the user stops scrolling.<div id="app">
<section id="page1">Page 1 Content</section>
<section id="page2">Page 2 Content</section>
</div>
#app
{
height: 100vh;
}
section
{
position: relative;
width: 100%;
height: 100%;
}
Upvotes: 2
Views: 2417
Reputation: 23
you can give id to the last paragraph and link it somewhere like
<a href="#abrr">hello</a>
<p> long text </p>
<p> another section </p>
<p id="abrr"> last section where we have to go </p>
Upvotes: 0
Reputation: 1485
The first thing that should be noted here is that the scroll
event cannot be canceled. Hence it can be only be done by attaching event listener on wheel
or mousewheel
events (touchmove
if touch screen support is also required ).
By using these, I was able to come up with this. The idea here is to maintain a counter, which will increase/decrease its value on every wheel
event. If the counter reaches a certain threshold, the scroll function will be triggered. Counter will reset back to 0, N number of miliseconds after stopping the mouse wheel.
Hence in order to trigger the scroll function, the mouse wheel must be turned a certain number of times to reach the threshold within the time limit of N milliseconds.
The drawback in this approach is that the body
element is given overflow:hidden
property to hide the scrollbar. Otherwise, users will be able to scroll the page without the desired effect. If this is not a problem, then the overflow
property can be removed.
Also, the touchmove
event is not handled in this example but the implementation for that will also be similar.
$(document).ready(function() {
const COUNTER_THRESHOLD = 5; // Change this to decrease/increase senstivity
const COUNTER_RESET_DURATION = 400;
let animating = false;
let counter = 0;
function resetDelta() {
counter = 0
}
let deboucncedReset = debounce(resetDelta, COUNTER_RESET_DURATION);
function handleScroll(event) {
//event.wheelDelta can be positive or negative based on the direction of scroll
counter += 1 * (Math.sign(event.wheelDelta));
//Scroll down if value of counter is negative and absolute value is greater than threshold
if (!animating && (Math.abs(counter) >= COUNTER_THRESHOLD) && counter < 0) {
let targetSection = $('section.active').next('section');
if (targetSection.length) {
scrollToSection(targetSection);
}
}
//Scroll up if value of counter is positive and absolute value is greater than threshold
else if (!animating && (Math.abs(counter) >= COUNTER_THRESHOLD) && counter > 0) {
let targetSection = $('section.active').prev('section');
if (targetSection.length) {
scrollToSection(targetSection);
}
}
// prevent default scrolling behaviour of mouse wheel
event.preventDefault()
//Reset counter to 0 , 400 miliseconds after stopping the mousewheel
deboucncedReset()
}
function scrollToSection(target) {
animating = true;
$('html, body').animate({
scrollTop: target.offset().top
}, 800, function() {
animating = false;
$('section.active').removeClass('active');
target.addClass('active');
});
}
function debounce(func, delay) {
let debounceTimer
return function() {
const context = this
const args = arguments
clearTimeout(debounceTimer)
debounceTimer
= setTimeout(() => func.apply(context, args), delay)
}
}
//Test support for passive listeners
let supportsPassive = false;
try {
let options = Object.defineProperty({}, 'passive', {
get: function() {
supportsPassive = true;
}
});
window.addEventListener("testPassive", null, options);
window.removeEventListener("testPassive", null, options);
} catch (e) {}
let wheelOptions = supportsPassive ? {
passive: false
} : false;
// Older browsers used 'mousewheel' event
let wheelEvent = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel';
document.addEventListener(wheelEvent, handleScroll, wheelOptions);
});
body {
overflow: hidden;
}
#app {
height: 100vh;
}
section {
position: relative;
width: 100%;
height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="app">
<section id="page1" class="active">
<h2>Section 1</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Dolores sequi quaerat officia non sunt sit, assumenda ullam itaque eos natus sed, aliquam adipisci consectetur nemo eum a reprehenderit fuga, ut consequatur beatae tenetur debitis. Officiis,
quod vitae sapiente tempore odit, quas nemo minus cupiditate laboriosam et cum accusantium porro quam hic soluta? Blanditiis assumenda suscipit accusamus laborum modi, cumque consequatur velit asperiores eius consectetur deserunt fugiat aperiam
recusandae quibusdam, dolore alias doloribus ut quis, voluptatem dolorum dolores harum unde magni. Commodi ducimus distinctio, quos ipsa, itaque illo nostrum laboriosam corporis sunt ad perferendis laborum ut natus magni dolore unde asperiores!</p>
</section>
<section id="page2">
<h2>Section 2</h2>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Repellendus, consequuntur enim ab dolorem rem, animi voluptates ipsam sequi nisi, dolores quod. Unde molestias facere autem nam error laboriosam eum nisi! Placeat voluptatum voluptate aspernatur.
Laboriosam nulla eaque culpa corporis consequuntur suscipit temporibus sed, totam, quia sit aut beatae sunt nihil ducimus fugit dolorum inventore minus dolorem modi eius! Aliquid distinctio sed dolorem? Quos ipsum optio fugit asperiores eligendi
vitae saepe nostrum. Eius minus recusandae quaerat. Fuga inventore temporibus doloremque sequi officia voluptatibus explicabo ad? Distinctio molestiae cupiditate obcaecati eum consequatur, error, illo quidem, maxime expedita veniam assumenda alias
culpa laudantium!</p>
</section>
</div>
To make it fully functional, arrow keys and space bar also needs to be handled. But that should be a relatively easy thing to handle.
Upvotes: 3