Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll to position WITHIN a div (not window) using pure JS

PURE JS ONLY PLEASE - NO JQUERY

I have a div with overflow scroll, the window (html/body) never overflows itself.

I have a list of anchor links and want to scroll to a position when they're clicked.

Basically just looking for anchor scrolling from within a div, not window.

window.scrollTo etc. don't work as the window never actually overflows.

Simple test case http://codepen.io/mildrenben/pen/RPyzqm

JADE

nav
  a(data-goto="#1") 1
  a(data-goto="#2") 2
  a(data-goto="#3") 3
  a(data-goto="#4") 4
  a(data-goto="#5") 5
  a(data-goto="#6") 6

main
  p(data-id="1") 1
  p(data-id="2") 2
  p(data-id="3") 3
  p(data-id="4") 4
  p(data-id="5") 5
  p(data-id="6") 6

SCSS

html, body {
  width: 100%;
  height: 100%;
  max-height: 100%;
}

main {
  height: 100%;
  max-height: 100%;
  overflow: scroll;
  width: 500px;
}

nav {
  background: red;
  color: white;
  position: fixed;
  width: 50%;
  left: 50%;
}

a {
  color: white;
  cursor: pointer;
  display: block;
  padding: 10px 20px;
  &:hover {
    background: lighten(red, 20%);
  }
}

p {
  width: 400px;
  height: 400px;
  border: solid 2px green;
  padding: 30px;
}

JS

var links = document.querySelectorAll('a'),
    paras = document.querySelectorAll('p'),
    main  = document.querySelector('main');

for (var i = 0; i < links.length; i++) {
  links[i].addEventListener('click', function(){
    var linkID = this.getAttribute('data-goto').slice(1);
    for (var j = 0; j < links.length; j++) {
      if(linkID === paras[j].getAttribute('data-id')) {
         window.scrollTo(0, paras[j].offsetTop); 
      }
    }
  })
}

PURE JS ONLY PLEASE - NO JQUERY

like image 395
mildrenben Avatar asked Jul 13 '15 10:07

mildrenben


People also ask

How do I scroll to a specific div?

The scrollIntoView method: The scrollIntoView() is used to scroll to the specified element in the browser. Example: Using scrollIntoView() to scroll to an element.

How do you scroll to an element inside a div react?

Scroll to an Element With the React Refs (References): The most simple way is to use ref to store the reference of the element that you want to scroll to. And call myRef. current. scrollIntoView() to scroll it into the view.

How do I get the scroll position of an element?

To get or set the scroll position of an element, you follow these steps: First, select the element using the selecting methods such as querySelector() . Second, access the scroll position of the element via the scrollLeft and scrollTop properties.

How do I get scroll to bottom of div?

jQuery scroll to the bottom of div set the scrollTop property of a div's JavaScript to the value of scroll height property to scroll to the bottom. ScrollTop and height() methods in jQuery can be used to scroll a page from top to bottom automatically.


1 Answers

What you want is to set the scrollTop property on the <main> element.

var nav = document.querySelector('nav'),
    main  = document.querySelector('main');

  nav.addEventListener('click', function(event){
    var linkID,
      scrollTarget;
    if (event.target.tagName.toUpperCase() === "A") {
      linkID = event.target.dataset.goto.slice(1);
      scrollTarget = main.querySelector('[data-id="' + linkID + '"]');
      main.scrollTop = scrollTarget.offsetTop;
    }
  });

You'll notice a couple of other things I did different:

  • I used event delegation so I only had to attach one event to the nav element which will more efficiently handle clicks on any of the links.
  • Likewise, instead of looping through all the p elements, I selected the one I wanted using an attribute selector

This is not only more efficient and scalable, it also produces shorter, easier to maintain code.

This code will just jump to the element, for an animated scroll, you would need to write a function that incrementally updates scrollTop after small delays using setTimeout.

var nav = document.querySelector('nav'),
    main  = document.querySelector('main'),
    scrollElementTo = (function () {
      var timerId;
      return function (scrollWithin, scrollTo, pixelsPerSecond) {
        scrollWithin.scrollTop = scrollWithin.scrollTop || 0;
        var pixelsPerTick = pixelsPerSecond / 100,
          destY = scrollTo.offsetTop,
          direction = scrollWithin.scrollTop < destY ? 1 : -1,
          doTick = function () {
            var distLeft = Math.abs(scrollWithin.scrollTop - destY),
              moveBy = Math.min(pixelsPerTick, distLeft);
            scrollWithin.scrollTop += moveBy * direction;
            if (distLeft > 0) {
              timerId = setTimeout(doTick, 10);
            }
          };
        clearTimeout(timerId);
        doTick();
      };
    }());

nav.addEventListener('click', function(event) {
  var linkID,
    scrollTarget;
  if (event.target.tagName.toUpperCase() === "A") {
    linkID = event.target.dataset.goto.slice(1);
    scrollTarget = main.querySelector('[data-id="' + linkID + '"]');
    scrollElementTo(main, scrollTarget, 500);
  }
});

Another problem you might have with the event delegation is that if the a elements contain child elements and a child element is clicked on, it will be the target of the event instead of the a tag itself. You can work around that with something like the getParentAnchor function I wrote here.

like image 193
Useless Code Avatar answered Oct 03 '22 02:10

Useless Code