最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I "snap" scroll to the nearest predefined position? - Stack Overflow

programmeradmin3浏览0评论

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?

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?

Share Improve this question asked Dec 7, 2012 at 2:52 Isaac LubowIsaac Lubow 3,5735 gold badges40 silver badges57 bronze badges
Add a comment  | 

5 Answers 5

Reset to default 6

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?

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>

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:

  • Vertical: https://jsfiddle.net/x9z5tpye/
  • Horizontal: https://jsfiddle.net/bwsyn6q4/

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();

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";
发布评论

评论列表(0)

  1. 暂无评论