9

I can’t wrap my head around it.

The element exists in a nested hierarchy of multiple scrollable DIV elements rather than in a single scrollable document window.

One of my headaches is how scrolled.offsetParent is document.body (colour papayawhip in test code below) rather than scrollable (colour pink).

Solutions to this problem based on JQuery and other libraries are acceptable only as complementary – for the benefit of other users, not mine.

Test code

(Original location: JSFiddle.)

function ReportExpression(ExpressionString) {
    return ExpressionString + " == " + eval(ExpressionString) + "\n";
}

function ButtonClick() {
    var scrollable = document.querySelector('#scrollable');
    var scrolled = document.querySelector('#scrolled');
    alert(
        ReportExpression("scrollable.scrollTop") +
        ReportExpression("scrolled.offsetTop") +
        ReportExpression("(scrolled.offsetParent == document.body)")
    );
    scrollable.scrollTop = scrolled.offsetTop;
}
html {background-color: white;}
body {text-align: center; background-color: papayawhip;}
#page {display: inline-block; text-align: left; width: 500px; height: 500px;
    overflow: auto; background-color: powderblue; padding: 10px;}
#scrollable {height: 500px; overflow: auto; background-color: pink;}
<body>
  <div id="page">
    <button onClick="ButtonClick();">Scroll</button>
    <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
    <div id="scrollable">
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <text id="scrolled">I want to scroll all scrollbars to this element.</text>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
    </div>
    <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
  </div>
</body>

Articles that I have studied

  1. How do I scroll to an element using JavaScript?
  2. http://www.quirksmode.org/js/findpos.html
  3. How to scroll to an element inside a div?
7vujy0f0hy
  • 8,741
  • 1
  • 28
  • 33
  • How do I embed the above test code to let StackOverflow users try it live? – 7vujy0f0hy May 10 '16 at 11:42
  • You can try setting up a fiddle (https://jsfiddle.net/) and pasting the link here. – Marc Compte May 10 '16 at 11:50
  • I’ve just discovered [`Element.scrollIntoView()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView). It would solve my problem if it weren’t a Working Draft specification. – 7vujy0f0hy May 10 '16 at 11:51
  • Just realised that `eval(ExpressionString)` in my code works as expected only by some lucky stroke. It shouldn’t evaluate expressions that contain local variables from other functions. – 7vujy0f0hy May 10 '16 at 17:25

3 Answers3

8

How about this?:

function ButtonClick() {
  var page = document.querySelector('#page');
  var scrollable = document.querySelector('#scrollable');
  var scrolled = document.querySelector('#scrolled');
  page.scrollTop = scrollable.offsetTop-page.offsetTop;
  scrollable.scrollTop = scrolled.offsetTop-scrollable.offsetTop;
}
Arg0n
  • 8,283
  • 2
  • 21
  • 38
  • I love it! Not only your solution works, but also makes me comprehend offset relationships. I like all answers in this thread so far. Shame I can’t upvote any due to my novice status. – 7vujy0f0hy May 10 '16 at 12:54
  • 2
    Alright. I’m picking your answer as my favourite. @Joey’s solution is awesomely simple but is less suitable for bookmarklets because a bookmarklet needs to deal with received HTML code without necessary HREF anchors. And yours has an extra educational value for me. – 7vujy0f0hy May 10 '16 at 13:16
  • I have created a library function based on your solution: `function ScrollDivTreeIntoView(dt) {for (var i = dt.length - 1; i >= 1; --i) dt[i].scrollTop = dt[i - 1].offsetTop - dt[i].offsetTop;}`. It reduces scrolling the whole nested DIV tree to a one-liner: `ScrollDivTreeIntoView([scrolled, scrollable, page])`. ([Fiddle](https://jsfiddle.net/262amaxL/7/)) – 7vujy0f0hy May 10 '16 at 23:15
  • For my own reference when I need this kind of thing in the future: page = container with scrollbar, scrollable = nested container with scrollbar, scrolled = target element to scroll to. Make sure `scrollBehavior: "smooth"` is set on the containers with scrollbars or the animation won't be smooth. `scrollIntoView` was hot garbage, and not well supported across browsers for certain settings. – 55 Cancri Feb 11 '22 at 01:24
4

Just make it like a href anchor and go to that anchor.

<button onClick="document.location+='#scrolled';return false;">Scroll</button>
Joey
  • 361
  • 1
  • 4
  • To be honest... that will do the job too. So simple that I haven’t thought about it. A bit dodgy in bookmarklets though because will require converting existing HTML elements into HREF anchors. Perhaps that’s why I haven’t thought about it. But it will work. Thank you! – 7vujy0f0hy May 10 '16 at 12:59
2

According to the first of the links you said you studied, I have applied one solution from there.

    element = document.getElementById("scrollable");
    alignWithTop = true;
    element.scrollIntoView(alignWithTop);

    elementB = document.getElementById("scrolled");
    alignWithTopB = true;
    elementB.scrollIntoView(alignWithTopB);

Live demo: https://jsfiddle.net/yt22fwc0/

andreini
  • 188
  • 1
  • 3
  • 17
  • I would love this function but, according to [`Element.scrollIntoView()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView), it’s a Working Draft specification. In addition, @AnchalAgrawal said in that thread: “I tried using scrollIntoView but it didn't work properly because my webpage had multiple divs. It will work if you have only one main window where focus lies. This is the best solution I have come across if you don't want to use jQuery which I didn't want to.” – 7vujy0f0hy May 10 '16 at 12:23
  • 1
    Ok, I understand now. Also, to fix the "Uncaught ReferenceError: ButtonClick is not defined" in JSFiddle, click on the Gear icon next to JAVASCRIPT and change the load type to "No wrap - ". – andreini May 10 '16 at 12:27
  • 1
    1. I may still use your solution in my personal bookmarklets because it works and is very convenient. 2. My JSFiddle now works. Thanks! – 7vujy0f0hy May 10 '16 at 12:35