Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating Seamless nested scroll rollover

I am attempting to create a series of window sized divs with inner divs of variable sizes > window size. The catch is it needs to scroll as if the divs where not nested.

In short I want THIS:

css{
     block{ height:100wh; }
     innerBlockSmall{ height:100wh; }
     innerBlockLarge{ height:200wh; }
}


<div class="block">
    <div class="innerBlockLarge"></div>
</div>
<div class="block">
    <div class="innerBlockSmall"></div>
</div>

https://jsfiddle.net/cbuh8psd/

to act just like THIS

css{
     innerBlockSmall{ height:100wh; }
     innerBlockLarge{ height:200wh; }
}

    <div class="innerBlockLarge"></div>
    <div class="innerBlockSmall"></div>

https://jsfiddle.net/t6zrvo7u/1/

Unfortunately scroll "Focus" is triggered by hovering over the scrollable element. In this case it is an undesirable behavior.

There are 2 possible solutions that I am currently aware of.

  1. Manually Assigning scroll "Focus" via javascript. (Optimal)

  2. Completely overwriting default HTML scrolling javascript, for example the library ISCROLL5.
    (ok, if the performance hit is small)

Unfortunately after looking through developer.mozilla's HTML5 documentation I have not run across any way to "Focus" scrolling to an element via javascript.

As for option 2 : ISCROLL5 has had an undesirable performance hit with over ~15-20 scrolling divs.

I am hoping I am missing something here, any solutions, fixes, or advice would be much appreciated.

like image 390
Burdock Avatar asked May 27 '15 06:05

Burdock


2 Answers

I have no idea why you would wish to do this, but the only way I can think of achieving the effect you want is along the lines of recreating the scrollbar, the good news however is that this needs not come at the cost of losing your native like experience.

Sadly I can't remember the project I wrote this code for, though one way to achieve this is to make yourself a scrollbar component. This scrollbar component would indeed provide a fake scrollbar, but provide a native like interface. So, how do you do this?

  1. You determine the width of the scrollbar by taking the difference between an element with and without overflow: scroll. Let this be scrollWidth
  2. You create a <div> with overflow: auto of width scrollWidth and position: fixed this in place on the right side of the body. Let the scrollTop property be scrollPosition.
  3. Inside the element you add another <div> with width 0 (this at least works in Chrome, check whether other browsers treat this differently) and let height be documentLength.
  4. Now, you can fully control the scrollbar by setting documentLength and scrollPosition any way you wish to. In your case you would set documentLength as the combined scrollHeights of each element and scrollPosition based on the relative scrollTop's in those nodes.

A very basic demonstration of the concept (not the implementation) can be found in this jsfiddle (note the width of the scrollbar is fixed to 20px in this case and there is no dynamic code whatsoever).

like image 25
David Mulder Avatar answered Sep 28 '22 14:09

David Mulder


This solution allows scrolling over entire document while keeping the possibility of scrolling each nested div with mouse. I hope I understood you correctly.

This is just a concept, it does not prevent nested elements from scrolling along with window. But it can be improved.

Array.prototype.slice.call( document.getElementsByClassName('sbRemover') )
.forEach(function (div) {
    var scroll = 0,
        mousedown = false,
        mouseBtnHandler = function (e) {
            mousedown = e.type == 'mousedown';
        }
    
    div.addEventListener('scroll', function (e) {
        // Change of div's scrollTop. Negative when scrolling down
        var diff = scroll - e.target.scrollTop;
        // Save new scroll value to be able to compare with it later
        scroll = e.target.scrollTop;
        // Do nothing when div is scrolled by dragging the scrollbar
        if (!mousedown) {
            // Scroll the window to the same amount of pixels the div was scrolled
            window.scrollTo(window.pageXOffset, window.pageYOffset - diff);
        }
    });
    div.addEventListener('mouseup', mouseBtnHandler);
    div.addEventListener('mousedown', mouseBtnHandler);
});
body, div {
    margin: 0;
    padding: 0;
}
.block{
    position: relative;
    width:100vw;
    height:100vh;
    overflow: hidden;
    z-index: 1;
    opacity: 100;
}
.sbRemover{
    width:100%;
    height:100%;
    padding-right:15px;
    overflow: auto;
}
.largeContent{
    height:225vh;
}
.smallContent{
    height:100vh;
}
<div id="simpleCanvas">
  <div class="block" style="background-color: blue">
    <div class="sbRemover">
      <div id="ok" class="largeContent" style="background-image: url('http://silviahartmann.com/background-tile-art/images/grey-repeating-background-8.jpg');"></div>
    </div>
  </div>
  <div class="block" style="background-color: red;">
    <div class="sbRemover">
      <div class="largeContent" style="background-image: url('http://a1star.com/images/star--background-seamless-repeating9.jpg');"></div>
    </div>
  </div>
  <div class="block" style="background-color: green">
    <div class="sbRemover">
      <div class="smallContent"></div>
    </div>
  </div>
  <div class="block" style="background-color: blue">
    <div class="sbRemover">
      <div class="smallContent"></div>
    </div>
  </div>
  <div class="block" style="background-color: red;">
    <div class="sbRemover">
      <div class="largeContent" style="background-image: url('http://people.stfx.ca/x2011/x2011ane/info102/assignment1/11500341-abstract-colorful-repeating-background.jpg');"></div>
    </div>
  </div>
  <div class="block" style="background-color: green">
    <div class="sbRemover">
      <div class="smallContent"></div>
    </div>
  </div>
</div>
like image 59
Dmytro Vyprichenko Avatar answered Sep 28 '22 16:09

Dmytro Vyprichenko