No tricks to make a smooth scroll through onscroll fail. The problem is that during the rotation of the mouse wheel, 5-12 onwheel events take off, which are transformed into onscroll. Your code tries to digest them - and it turns out jumps.
The scroll event does not pop up, so the standard scroll cannot be canceled via preventDefault.
I messed around with this problem for quite a while. I had to intercept onWheel and animate smoothly to the right place. I did the animation on jQuery, here I didn’t set the animation as part of the response to the javascript - just scrolling the windows and transfrom: translate .
Important note. The browser handles top and transform differently, there are examples on the Web that transform works much more smoothly.
The code below intercepts onWheel, accumulates events for 150ms to track the complete single movement of the wheel, then raises the animating flag. During the "animation" the script does not perceive any new scrolling events, scrolls the window once to the full previously scrolled value of the scroll, changes the position of the black square through the transform and after 100ms clears the animating flag.
These values, 150 and 100 ms, are purely empirical and are tailored to a specific task, especially if the script animates the element.
// Так квадрат дергается // window.onscroll = function() { // document.getElementsByTagName('div')[0].style.transform = 'translateY(' + window.pageYOffset + 'px' + ')'; // return false; // }; // А так - не дергается var animating = false; var timeoutID; function onWheel(event) { event = event || window.event; var pos = event.deltaY || event.detail || event.wheelDelta; console.log(pos); if (animating) { finalPos = finalPos + pos; event.preventDefault(); return false; } if (pos > 0) { // downscroll code if (!animating) { // Scroll animating = true; finalPos = pos; event.preventDefault(); clearTimeout(timeoutID); timeoutID = setTimeout(function() { console.log('scroll to ' + finalPos); window.scrollTo(window.scrollX, window.scrollY + finalPos); document.getElementsByTagName('div')[0].style.transform = 'translateY(' + window.pageYOffset + 'px' + ')'; setTimeout(function() { animating = false; }, 100); }, 150); } } else { // upscroll code if (!animating) { // Scroll animating = true; finalPos = pos; event.preventDefault(); clearTimeout(timeoutID); timeoutID = setTimeout(function() { console.log('scroll to ' + finalPos); window.scrollTo(window.scrollX, window.scrollY + finalPos); document.getElementsByTagName('div')[0].style.transform = 'translateY(' + window.pageYOffset + 'px' + ')'; setTimeout(function() { animating = false; }, 100); }, 150); } } } if (window.addEventListener) { if ('onwheel' in document) { window.addEventListener("wheel", onWheel, {passive: false, capture: true}); // IE9+, FF17+, Ch31+ } else if ('onmousewheel' in document) { window.addEventListener("mousewheel", onWheel); // устаревший вариант события } else { window.addEventListener("MozMousePixelScroll", onWheel); // Firefox < 17 } } else { window.attachEvent("onmousewheel", onWheel); // IE8- }
You can see the working code here in jsfiddle or here on the page of the test site .
margin? - SLy_huhposition: absolute; top...pxposition: absolute; top...pxtwitches - Yurifixed, with the exception that when it is fully scrolled up, it is marked with a few pixels. MB, when scrolling to2+pxit is easy to assign a class to it withposition: fixed; top:0;position: fixed; top:0;? - SLy_huh