Hello.

There is a small code that sets the value of the top the block depending on the position of the scroll. The problem is that not all browsers display it smoothly, i.e. when scroll'e there are sharp jumps (browser: IE , Opera <11 , etc.). How to remove these jumps and make completely smooth movements?

Code:

 window.onscroll = function() { document.getElementsByTagName('div')[0].style.marginTop = window.pageYOffset + 'px'; }; 
 body {height: 2000px; } div { width: 200px; height: 200px; background-color: black; } 
 <div></div> 

Display with jumps:

enter image description here

In the picture there are small jumps, but with different objects and different browsers - jumps of different sizes.

Link to third-party editor: jsfiddle-gjx7ecd4

  • And it is necessary through the margin ? - SLy_huh
  • @SLy_huh, it doesn't matter here. It is with position: absolute; top...px position: absolute; top...px twitches - Yuri
  • Well, in the sense that the behavior of the block is very similar to fixed , with the exception that when it is fully scrolled up, it is marked with a few pixels. MB, when scrolling to 2+px it is easy to assign a class to it with position: fixed; top:0; position: fixed; top:0; ? - SLy_huh
  • @SLy_huh, you can. But I thought you could somehow remove these loops from the script. Add your own version and I will accept it :) - Yuri

2 answers 2

The block's behavior is much like fixed, with the exception that when the window is fully scrolled up, it blinks a few pixels. Perhaps the solution would be to assign him a class with the necessary parameters if the amount of scrolling of the window is greater than its initial indent.

 var elem = document.getElementById('test'); //получаем целевой элемент var style = elem.currentStyle || window.getComputedStyle(elem);/* тк, если напрямую обратиться к свойству style, то мы получим список правил для, непосредственно, ЭЛЕМЕНТА, нам же нужен именно список правил, для таблицы стилей(первое выражение для IE)*/ var scrollOffset = style.marginTop;//Собственно, получаем начальный отступ из стилей scrollOffset = scrollOffset.substr(0, scrollOffset.length-2)//убираем злосчастные `px` window.onscroll = function() { if(window.pageYOffset > scrollOffset){ elem.className = 'scrolled'; return; } elem.className = ''; }; 
 body {height: 2000px; padding: 0px; margin: 0px;} div#test { width: 200px; height: 200px; background-color: black; margin-top: 7px; } .scrolled{ position: fixed; margin-top: 0px !important; /*Свойства стилей для id перекрывают свойства для классов, посему так, но для новичков: это BAD PRACTICE!*/ box-sizing: border-box; background-color: red !important; /*Просто, дабы понимать, что сейчас на нем висит класс*/ } 
 <div id='test'></div> 

    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 .

    • I certainly could be wrong, but fiddle refers to the author's fiddle. And on the test page, the scroll frantically "lags", apparently due to too much waiting time. - SLy_huh
    • moment, thank you. Corrected. - KAGG Design
    • And now on the test page, if you use mmb , or pageUp/pageDown , or a пробел for a scroll, the event is not triggered, the square is still. - SLy_huh
    • Just the opposite - the square when pageUp / pageDown flies away. Because my code intercepts only onWheel. - KAGG Design
    • Well, relative to the body it stands still, yes, and relative to the viewport it moves. But, as it seems to me, this is not exactly the behavior that the author expects when scrolling the page not with a wheel. In addition, on the gif - the author pulls the page for the slider on the scroll, while the div remains fixed on top of the viewport. In your version, it stays at the top of the body , not the viewport. - SLy_huh