Reputation: 3573
I have a website that is essentially four divs - each of which is set to the height of the window so that the total document is four times the height of the window.
The idea is that a click on a div advances the scroll by one "window height" - which works fine, like this:
// on click event
if(cur_frame<number_slides){
scrolling = true;
$('html,body').animate({scrollTop:window_height*cur_frame},function(){
scrolling=false;
});
}
After the user scrolls the page manually, however, I'd like to "snap" the position to the nearest multiple of the window height - so a given div is once again centered on the screen. I tried using a timeout, figuring that a small delay would keep it from triggering a thousand times a second...
// on scroll event
clearTimeout(scroll_timer);
if(!scrolling) scroll_timer = setTimeout(function(){
if(cur_scroll!=window_height*(cur_frame-1)) {
scrolling = true;
$('html,body').stop().animate({scrollTop:window_height*(cur_frame-1)},function(){
scrolling = false;
});
}
},100); //20? 400? 1000?
...but couldn't strike a balance between the script fighting the user over scroll position, or a seriously long delay that defeats the "snapping" effect.
Any suggestions how this might be achieved?
Upvotes: 5
Views: 29138
Reputation: 1167
What about using a simple scrollTo
? Plain Javascript and CSS used, no frameworks or libraries.
Here are two examples, one for vertical scrolling and the other for horizontal scrolling:
Upvotes: 4
Reputation: 89
If you want to consider a cross-browser javascript re-implementation of the native CSS Scroll Snap spec, as already answered here: How to emulate CSS Scroll Snap Points in Chrome?, you can use this library:
The main reason to use this instead of the native css solution is that it works in all modern browsers and has a customizable configuration to allow custom timing in transitions and scrolling detection.
The library re-implements the css snapping feature using vanilla javascript easing functions, and works using the values of the container element's scrollTop
/scrollLeft
properties and the scroll Event Listener
Here is an example that shows how to use it:
import createScrollSnap from 'scroll-snap'
const element = document.getElementById('container')
const { bind, unbind } = createScrollSnap(element, {
snapDestinationX: '0%',
snapDestinationY: '90%',
timeout: 100,
duration: 300,
threshold: 0.2,
snapStop: false,
easing: easeInOutQuad,
}, () => console.log('snapped'))
// remove the listener
// unbind();
// re-instantiate the listener
// bind();
Upvotes: 2
Reputation: 1116
There is a CSS spec for this, and it is well supported with native rendering and very nice touch behavior except on Chrome: http://caniuse.com/#feat=css-snappoints
For the laggard browser, there's a polypill: https://github.com/ckrack/scrollsnap-polyfill
See also How to emulate CSS Scroll Snap Points in Chrome?
Upvotes: 6
Reputation: 2668
The jquery scrollsnap plugin for this supports down to IE9.
What you're looking for is called "Scroll Snap".
<script src="demo/foundation/javascripts/jquery.js"></script>
<script src="src/jquery.event.special.js"></script>
<script src="src/jquery.easing.min.js"></script>
<script src="src/jquery.scrollsnap.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$(document).scrollsnap({
snaps: '.snap',
proximity: 50
});
});
</script>
Upvotes: 6
Reputation: 1790
You could do this with javascript or for a slightly simpler and older solution you can use page anchors. If you change your document.location.hash to an anchor that exists in the page then the browser will scroll to it. So in your HTML put some anchors in the page:
<a name="anchor1" id="anchor1"></a>
then in your js put:
document.location.hash = "anchor1";
Upvotes: 0