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?
4
  • How do I embed the above test code to let StackOverflow users try it live? Commented May 10, 2016 at 11:42
  • You can try setting up a fiddle (jsfiddle.net) and pasting the link here. Commented May 10, 2016 at 11:50
  • I’ve just discovered Element.scrollIntoView(). It would solve my problem if it weren’t a Working Draft specification. Commented May 10, 2016 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. Commented May 10, 2016 at 17:25

3 Answers 3

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;
}
Sign up to request clarification or add additional context in comments.

4 Comments

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.
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.
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)
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.
4

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

<button onClick="document.location+='#scrolled';return false;">Scroll</button>

1 Comment

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!
3

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/

3 Comments

I would love this function but, according to 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.”
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 - <In head>".
1. I may still use your solution in my personal bookmarklets because it works and is very convenient. 2. My JSFiddle now works. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.