How to make the synchronization of two sections of the scroll Divs smoother

I am trying to synchronize two scrollable DIVS scroll positions.

Methods used:

Method 1 : The scroll event sets the scrollTop of another DIV. problem: the scroll event executed at the end and the user interface is sluggish in iOS safari.

Method 2 : Use setInterval to synchronize both scroll positions. Problem: iOS does not perform timer functions during scrolling, so the scroll positions are synchronized at the end. Again, this is more sluggish. Trying to fix the timers, as mentioned in many blogs, but still without grace.

Method -3 : I tried the custom scrollbar, so iScroll tried to synchronize as with the scroll event Problem: this seems better, but on iOS it is still sluggish !!!

Method -4 : I tried a custom scrollbar, so iScroll tried to synchronize as with the scroll event Problem: iScroll is used, but using timers, depending on the onScroll event, But during touchmove iOS is busy providing animations rather fulfilling the required timers before touching. The code below refers to this method. It is also sluggish.

 var active = .., other = ... // active : active Scrolling element // other : Element to be in sync with active window.setInterval(function () { var y; if (active) { y = active.y; } else { return; } var percentage = -y / (active.scrollerHeight - active.wrapperHeight); var oscrollTop = percentage * (other.scrollerHeight - other.wrapperHeight); if (-other.maxScrollY >= toInt(oscrollTop)) { other.scrollTo(0, -toInt(oscrollTop)); } }, 20); 

How can I synchronize scroll positions with two scrollable DIVS anti-aliasing. Please offer me something, it annoys me.

+6
source share
1 answer

relying on scroll events (OPs 1 method), suitable for desktop implementation. the scroll event is fired before the screen refreshes. on mobile devices, especially iOS, this is not the case. due to limited resources, the scroll event is triggered only after the user has performed (raised his finger) the scroll operation.

manual scrolling

in order to have a scroll event when a user scrolls on iOS, you need to manually scroll.

  • register a touchstart event. and get the first touch:

     var element1 = document.getElementById('content1'); var element2 = document.getElementById('content2'); var activeTouch = null; var touchStartY = 0; var element1StartScrollTop = 0; var element2scrollSyncFactor = 0; document.addEventListener('touchstart', function(event) { event.preventDefault(); var touch = event.changedTouches[0]; if ( activeTouch == null ) { // implement check if touch started on an element you want to be scrollable // save a reference to the scrolling element for the other functions activeTouch = touch; touchStartY = touch.screenY; // if scroll content does not change do this calculation only once to safe compute and dom access time while animating calcSyncFactor(); } }); function calcSyncFactor() { // calculate a factor for scroll areas with different height element2scrollSyncFactor = (element2.scrollHeight - element2.clientHeight) / (element1.scrollHeight - element1.clientHeight); } 
  • update your scroll position when moving your finger:

     document.addEventListener('touchmove', function() { for ( var i = 0; i < event.changedTouches.length; i++ ) { var touch = event.changedTouches[i]; if ( touch === activeTouch ) { var yOffset = touch.screenY - touchStartY; element1.scrollTop = element1StartScrollTop + (0 - yOffset); syncScroll(); break; } } }); function syncScroll() { element2.scrollTop = Math.round(element1.scrollTop * element2scrollSyncFactor); } 

    you can add a check that starts scrolling only after the user has moved his finger a few pixels. this way, if the user clicks on an item, the document will not scroll some pixels.

  • cleaning after the user lifts a finger:

     document.addEventListener('touchend', touchEnd); document.addEventListener('touchcancel', touchEnd); function touchEnd(event) { for ( var i = 0; i < event.changedTouches.length; i++ ) { var touch = event.changedTouches[i]; if ( touch === activeTouch ) { // calculate inertia and apply animation activeTouch = null; break; } } } 

    To make the scroll look more natural, apply the iOS rubber band effect and inertia. calculate the scroll speed by comparing the last touchMove yOffset with the previous one. from this speed apply animation (e.g. css transition) that slowly stops scrolling

see FIDDLE . see the result in iOS . the violin only implements a solution for touch devices. for desktop devices, use the OP 1 method. implement a condition that checks which method to use depending on the device.

how to apply inertia with css transitions

could be animated in javascript using requestAnimationFrame . perhaps a more efficient way for mobile devices is to use css transforms or css animations. although the scroll position of the elements cannot be animated by css.

  • change the html structure to.

    • div: container with overflow: hidden

      • div: content position: absolute

        depending on the size of the content, use the css -webkit-transform: translateZ(0) property in the content div. this will create a new layer with its own reference surface, which will be arranged on the GPU.

  • implement the functions described above so that they animate the contents of the top point in time scrollTop

     var element1 = document.getElementById('content1'); var element2 = document.getElementById('content2'); var activeTouch = null; var touchStartY = 0; var element1StartScrollTop = 0; var element2scrollSyncFactor = 0; var offsetY = 0; var lastOffsetY = 0; document.addEventListener('touchstart', function(event) { event.preventDefault(); var touch = event.changedTouches[0]; if ( activeTouch == null ) { activeTouch = touch; touchStartY = touch.screenY; // use offsetTop instead of scrollTop element1StartScrollTop = element1.offsetTop; // if scroll content does not change do this calculation only once to safe compute time while animating calcSyncFactor(); // cancel inertia animations element1.style.webkitTransition = 'none'; element2.style.webkitTransition = 'none'; } }); function calcSyncFactor() { // calculate a factor for scroll areas with different height // use the div sizes instead of scrollTop element2scrollSyncFactor = (element2.clientHeight - element2.parentNode.clientHeight) / (element1.clientHeight - element1.parentNode.clientHeight); } document.addEventListener('touchmove', function() { for ( var i = 0; i < event.changedTouches.length; i++ ) { var touch = event.changedTouches[i]; if ( touch === activeTouch ) { lastOffsetY = offsetY; offsetY = touch.screenY - touchStartY; // use offsetTop instead of scrollTop element1.style.top = (element1StartScrollTop + offsetY) + 'px'; syncScroll(); break; } } }); function syncScroll() { element2.style.top = Math.round(element1.offsetTop * element2scrollSyncFactor) + 'px'; } document.addEventListener('touchend', touchEnd); document.addEventListener('touchcancel', touchEnd); function touchEnd(event) { for ( var i = 0; i < event.changedTouches.length; i++ ) { var touch = event.changedTouches[i]; if ( touch === activeTouch ) { applyInertia(); activeTouch = null; break; } } } 
  • when the user finishes scrolling and raises a finger, applies inertia

     function applyInertia() { var velocity = offsetY - lastOffsetY; var time = Math.abs(velocity) / 150; var element1EndPosition = element1.offsetTop + velocity; element1.style.webkitTransition = 'top ' + time + ease-out'; element1.style.top = element1EndPosition + 'px'; element2.style.webkitTransition = 'top ' + time + ease-out'; element2.style.top = Math.round(element1EndPosition * element2scrollSyncFactor) + 'px'; } 

    inertia is calculated by speed when the user lifts a finger. navigate with the values ​​to get the desired results. the rubber band effect can also be realized in this function. having no javascript related to applying css animation might be a trick. another way would be to log events to complete the transition. if the transition is completed and the scroll position is outside the container, apply a new transition that enlivens the content.

see FIDDLE . see the result in iOS .

+1
source

Source: https://habr.com/ru/post/974278/


All Articles