Components scroll synchronization with Javascript

Management of scrolls in different areas of your page it’s as easy to attach a listener to the component where the scrolls are shown in order to change the positioning properties of the simulated scrollable attached area when the scrollbars are used. A couple of things to keep in mind are that the javascript-scrolled area should have the same dimensions that the main one in order to handle the same amount of displacement with the scrolls, and depending on the need of explicitly  showing the secondary scrollbar or not CSS display property should be set properly.

A very basic example would be just moving this examples here, a couple of simple HTML boxes:

Lorem ipsum...
Lorem ipsum...

with its asociatted CSS properties:

#scrolled-block {
   overflow:auto;
}
#javascript-scrolled-block {
   overflow:hidden;
}
.content-box {
   background-color: #EEEEEE;
   margin:20px;
   padding:10px;
   width: 200px;
   height: 200px;
   float:left;
}

This produces the displayed result. Our purpose is to add an action listener to onScroll first component in order to get the second box moved when we scroll the first one:

Scrollable box

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc mollis ante ut sapien venenatis porttitor. Aliquam vel justo nec nisi mattis tempus
in eget magna. Sed vitae risus et nulla placerat laoreet. Pellentesque habitant morbi tristique
senectus et netus et malesuada fames ac turpis egestas. Duis vestibulum velit a sapien bibendum
laoreet. Nulla nec sapien et orci tincidunt tempor. Proin orci metus, egestas at sodales vitae, sodales vitae erat.

Self-scrolled box

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc mollis ante ut sapien venenatis porttitor. Aliquam vel justo nec nisi mattis tempus
in eget magna. Sed vitae risus et nulla placerat laoreet. Pellentesque habitant morbi tristique
senectus et netus et malesuada fames ac turpis egestas. Duis vestibulum velit a sapien bibendum
laoreet. Nulla nec sapien et orci tincidunt tempor. Proin orci metus, egestas at sodales vitae, sodales vitae erat.

listenToScroll();
function listenToScroll() {
scroll.block_ = document.getElementById(‘scrolled-block’);
scroll.jsblock_ = document.getElementById(‘javascript-scrolled-block’);
onScroll = function() {
scroll.jsblock_.scrollTop = scroll.block_.scrollTop;
};
scroll.block_.onscroll = onScroll;
}

listenToScroll();

function listenToScroll() {
    scroll.block_ = document.getElementById('scrolled-block');
    scroll.jsblock_ = document.getElementById('javascript-scrolled-block');
    onScroll = function() {
        scroll.jsblock_.scrollTop = scroll.block_.scrollTop; 
    };
    scroll.block_.onscroll = onScroll;
}

This strategy works fine for simultaneous synchronization but we have checked a different behavior for listeners attached to scrollbars in the different browser engines. In WebKIT based browsers with its Javascript engines (as Squirrelfish in Epiphany or v8 in Chrome), all listeners are processed when the browser implementation fiscally scrolls the component, so the movement is perfectly synchronized. For Gecko plus Tracemonkey, the effect that can be perceived is that scroll in the first component is slightly delayed. To avoid this, it’s necessary to scroll both components using Javascript, and creating a third element just with the scrollbar. The result can be checked evolving the previous example.

Self-scrolled box 1

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc mollis ante ut sapien venenatis porttitor. Aliquam vel justo nec nisi mattis tempus
in eget magna. Sed vitae risus et nulla placerat laoreet. Pellentesque habitant morbi tristique
senectus et netus et malesuada fames ac turpis egestas. Duis vestibulum velit a sapien bibendum
laoreet. Nulla nec sapien et orci tincidunt tempor. Proin orci metus, egestas at sodales vitae, sodales vitae erat.
Aliquam sed lorem a ante vestibulum pharetra. Nullam lobortis facilisis tincidunt. Quisque id libero ante, in aliquet orci.

Self-scrolled box 2

Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Nunc mollis ante ut sapien venenatis porttitor. Aliquam vel justo nec nisi mattis tempus
in eget magna. Sed vitae risus et nulla placerat laoreet. Pellentesque habitant morbi tristique
senectus et netus et malesuada fames ac turpis egestas. Duis vestibulum velit a sapien bibendum
laoreet. Nulla nec sapien et orci tincidunt tempor. Proin orci metus, egestas at sodales vitae, sodales vitae erat.
Aliquam sed lorem a ante vestibulum pharetra. Nullam lobortis facilisis tincidunt. Quisque id libero ante, in aliquet orci.

listenToSimulatedScroll();
function listenToSimulatedScroll() {
scroll.simulatedblock_ = document.getElementById(‘simulated-scrolled-block’);
scroll.jsblock1_ = document.getElementById(‘javascript-scrolled-block-1’);
scroll.jsblock2_ = document.getElementById(‘javascript-scrolled-block-2’);
onScroll = function() {
scroll.jsblock1_.scrollTop = scroll.simulatedblock_.scrollTop;
scroll.jsblock2_.scrollTop = scroll.simulatedblock_.scrollTop;
};
scroll.simulatedblock_.onscroll = onScroll;
}

listenToSimulatedScroll();
function listenToSimulatedScroll() {
	scroll.simulatedblock_ = document.getElementById('simulated-scrolled-block');   
	scroll.jsblock1_ = document.getElementById('javascript-scrolled-block-1');	
	scroll.jsblock2_ = document.getElementById('javascript-scrolled-block-2');	
    onScroll = function() {
        scroll.jsblock1_.scrollTop = scroll.simulatedblock_.scrollTop; 
        scroll.jsblock2_.scrollTop = scroll.simulatedblock_.scrollTop; 
    };
    scroll.simulatedblock_.onscroll = onScroll;
}

It would be necessary to remove the paddings, and that’s it.

#javascript-scrolled-block-1, #javascript-scrolled-block-2 {   
	overflow:hidden;
}
#simulated-scrolled-block {
    overflow:auto;
    background-color: #EEEEEE;
    padding-left:0;
    width: 5px;
}
.inner-simulated-block {
   height:300px;
}
.content-box {
    background-color: #EEEEEE;
    overflow:auto;
    padding-left:0;
    width: 5px;	
    margin:20px;
    padding:10px;
    height: 200px;
    float:left;
}
Lorem ipsum...
Lorem ipsum...

Things get really complicated when it’s necessary to scroll intersected areas inside a complex layout with the need to stick scrollable components over the main area, in a desktop application style approach, let’s say for instance a Gantt application layout. In this scenario we have to combine this technique with CSS positioning of related elements, manage its resizing and binding different methods to each dimension scrolling, but the main idea is the same one.