[javascript] How to scroll to an element inside a div?

I have a scrolled div and I want to have an event when I click on it, it will force this div to scroll to view an element inside. I wrote its JavasSript like this:

document.getElementById(chr).scrollIntoView(true);

but this scrolls all the page while scrolling the div itself. How to fix that?

I want to say it like this: MyContainerDiv.getElementById(chr).scrollIntoView(true);

This question is related to javascript html scroll

The answer is


Another example of using jQuery and animate.

var container = $('#container');
var element = $('#element');

container.animate({
    scrollTop: container.scrollTop = container.scrollTop() + element.offset().top - container.offset().top
}, {
    duration: 1000,
    specialEasing: {
        width: 'linear',
        height: 'easeOutBounce'
    },
    complete: function (e) {
        console.log("animation completed");
    }
});

You would have to find the position of the element in the DIV you want to scroll to, and set the scrollTop property.

divElem.scrollTop = 0;

Update:

Sample code to move up or down

  function move_up() {
    document.getElementById('divElem').scrollTop += 10;
  }

  function move_down() {
    document.getElementById('divElem').scrollTop -= 10;
  }

We can resolve this problem without using JQuery and other libs.

I wrote following code for this purpose:

You have similar structure ->

<div class="parent">
  <div class="child-one">

  </div>
  <div class="child-two">

  </div>
</div>

JS:

scrollToElement() {
  var parentElement = document.querySelector('.parent');
  var childElement = document.querySelector('.child-two');

  parentElement.scrollTop = childElement.offsetTop - parentElement.offsetTop;
}

We can easily rewrite this method for passing parent and child as an arguments


There are two facts :

1) Component scrollIntoView is not supported by safari.

2) JS framework jQuery can do the job like this:

parent = 'some parent div has css position==="fixed"' || 'html, body';

$(parent).animate({scrollTop: $(child).offset().top}, duration)

If you are using jQuery, you could scroll with an animation using the following:

$(MyContainerDiv).animate({scrollTop: $(MyContainerDiv).scrollTop() + ($('element_within_div').offset().top - $(MyContainerDiv).offset().top)});

The animation is optional: you could also take the scrollTop value calculated above and put it directly in the container's scrollTop property.


To scroll an element into view of a div, only if needed, you can use this scrollIfNeeded function:

_x000D_
_x000D_
function scrollIfNeeded(element, container) {_x000D_
  if (element.offsetTop < container.scrollTop) {_x000D_
    container.scrollTop = element.offsetTop;_x000D_
  } else {_x000D_
    const offsetBottom = element.offsetTop + element.offsetHeight;_x000D_
    const scrollBottom = container.scrollTop + container.offsetHeight;_x000D_
    if (offsetBottom > scrollBottom) {_x000D_
      container.scrollTop = offsetBottom - container.offsetHeight;_x000D_
    }_x000D_
  }_x000D_
}_x000D_
_x000D_
document.getElementById('btn').addEventListener('click', ev => {_x000D_
  ev.preventDefault();_x000D_
  scrollIfNeeded(document.getElementById('goose'), document.getElementById('container'));_x000D_
});
_x000D_
.scrollContainer {_x000D_
  overflow-y: auto;_x000D_
  max-height: 100px;_x000D_
  position: relative;_x000D_
  border: 1px solid red;_x000D_
  width: 120px;_x000D_
}_x000D_
_x000D_
body {_x000D_
  padding: 10px;_x000D_
}_x000D_
_x000D_
.box {_x000D_
  margin: 5px;_x000D_
  background-color: yellow;_x000D_
  height: 25px;_x000D_
  display: flex;_x000D_
  align-items: center;_x000D_
  justify-content: center;_x000D_
}_x000D_
_x000D_
#goose {_x000D_
  background-color: lime;_x000D_
}
_x000D_
<div id="container" class="scrollContainer">_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div id="goose" class="box">goose</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
  <div class="box">duck</div>_x000D_
</div>_x000D_
_x000D_
<button id="btn">scroll to goose</button>
_x000D_
_x000D_
_x000D_


User Animated Scrolling

Here's an example of how to programmatically scroll a <div> horizontally, without JQuery. To scroll vertically, you would replace JavaScript's writes to scrollLeft with scrollTop, instead.

JSFiddle

https://jsfiddle.net/fNPvf/38536/

HTML

<!-- Left Button. -->
<div style="float:left;">
    <!-- (1) Whilst it's pressed, increment the scroll. When we release, clear the timer to stop recursive scroll calls. -->
    <input type="button" value="«" style="height: 100px;" onmousedown="scroll('scroller',3, 10);" onmouseup="clearTimeout(TIMER_SCROLL);"/>
</div>
<!-- Contents to scroll. -->
<div id="scroller" style="float: left; width: 100px; height: 100px; overflow: hidden;">
    <!-- <3 -->
    <img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a" alt="image large" style="height: 100px" />
</div>
<!-- Right Button. -->
<div style="float:left;">
    <!-- As (1). (Use a negative value of 'd' to decrease the scroll.) -->
    <input type="button" value="»" style="height: 100px;" onmousedown="scroll('scroller',-3, 10);" onmouseup="clearTimeout(TIMER_SCROLL);"/>
</div>

JavaScript

// Declare the Shared Timer.
var TIMER_SCROLL;
/** 
Scroll function. 
@param id  Unique id of element to scroll.
@param d   Amount of pixels to scroll per sleep.
@param del Size of the sleep (ms).*/
function scroll(id, d, del){
    // Scroll the element.
    document.getElementById(id).scrollLeft += d;
    // Perform a delay before recursing this function again.
    TIMER_SCROLL = setTimeout("scroll('"+id+"',"+d+", "+del+");", del);
 }

Credit to Dux.


Auto Animated Scrolling

In addition, here are functions for scrolling a <div> fully to the left and right. The only thing we change here is we make a check to see if the full extension of the scroll has been utilised before making a recursive call to scroll again.

JSFiddle

https://jsfiddle.net/0nLc2fhh/1/

HTML

<!-- Left Button. -->
<div style="float:left;">
    <!-- (1) Whilst it's pressed, increment the scroll. When we release, clear the timer to stop recursive scroll calls. -->
    <input type="button" value="«" style="height: 100px;" onclick="scrollFullyLeft('scroller',3, 10);"/>
</div>
<!-- Contents to scroll. -->
<div id="scroller" style="float: left; width: 100px; height: 100px; overflow: hidden;">
  <!-- <3 -->
  <img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a" alt="image large" style="height: 100px" />
</div>
<!-- Right Button. -->
<div style="float:left;">
    <!-- As (1). (Use a negative value of 'd' to decrease the scroll.) -->
    <input type="button" value="»" style="height: 100px;" onclick="scrollFullyRight('scroller',3, 10);"/>
</div>

JavaScript

// Declare the Shared Timer.
var TIMER_SCROLL;
/** 
Scroll fully left function; completely scrolls  a <div> to the left, as far as it will go.
@param id  Unique id of element to scroll.
@param d   Amount of pixels to scroll per sleep.
@param del Size of the sleep (ms).*/
function scrollFullyLeft(id, d, del){
    // Fetch the element.
    var el = document.getElementById(id);
    // Scroll the element.
    el.scrollLeft += d;
    // Have we not finished scrolling yet?
    if(el.scrollLeft < (el.scrollWidth - el.clientWidth)) {
        TIMER_SCROLL = setTimeout("scrollFullyLeft('"+id+"',"+d+", "+del+");", del);
    }
}

/** 
Scroll fully right function; completely scrolls  a <div> to the right, as far as it will go.
@param id  Unique id of element to scroll.
@param d   Amount of pixels to scroll per sleep.
@param del Size of the sleep (ms).*/
function scrollFullyRight(id, d, del){
    // Fetch the element.
    var el = document.getElementById(id);
    // Scroll the element.
    el.scrollLeft -= d;
    // Have we not finished scrolling yet?
    if(el.scrollLeft > 0) {
        TIMER_SCROLL = setTimeout("scrollFullyRight('"+id+"',"+d+", "+del+");", del);
    }
}

Method 1 - Smooth scrolling to an element inside an element

_x000D_
_x000D_
var box = document.querySelector('.box'),_x000D_
    targetElm = document.querySelector('.boxChild'); // <-- Scroll to here within ".box"_x000D_
_x000D_
document.querySelector('button').addEventListener('click', function(){_x000D_
   scrollToElm( box, targetElm , 600 );   _x000D_
});_x000D_
_x000D_
_x000D_
/////////////_x000D_
_x000D_
function scrollToElm(container, elm, duration){_x000D_
  var pos = getRelativePos(elm);_x000D_
  scrollTo( container, pos.top , 2);  // duration in seconds_x000D_
}_x000D_
_x000D_
function getRelativePos(elm){_x000D_
  var pPos = elm.parentNode.getBoundingClientRect(), // parent pos_x000D_
      cPos = elm.getBoundingClientRect(), // target pos_x000D_
      pos = {};_x000D_
_x000D_
  pos.top    = cPos.top    - pPos.top + elm.parentNode.scrollTop,_x000D_
  pos.right  = cPos.right  - pPos.right,_x000D_
  pos.bottom = cPos.bottom - pPos.bottom,_x000D_
  pos.left   = cPos.left   - pPos.left;_x000D_
_x000D_
  return pos;_x000D_
}_x000D_
    _x000D_
function scrollTo(element, to, duration, onDone) {_x000D_
    var start = element.scrollTop,_x000D_
        change = to - start,_x000D_
        startTime = performance.now(),_x000D_
        val, now, elapsed, t;_x000D_
_x000D_
    function animateScroll(){_x000D_
        now = performance.now();_x000D_
        elapsed = (now - startTime)/1000;_x000D_
        t = (elapsed/duration);_x000D_
_x000D_
        element.scrollTop = start + change * easeInOutQuad(t);_x000D_
_x000D_
        if( t < 1 )_x000D_
            window.requestAnimationFrame(animateScroll);_x000D_
        else_x000D_
            onDone && onDone();_x000D_
    };_x000D_
_x000D_
    animateScroll();_x000D_
}_x000D_
_x000D_
function easeInOutQuad(t){ return t<.5 ? 2*t*t : -1+(4-2*t)*t };
_x000D_
.box{ width:80%; border:2px dashed; height:180px; overflow:auto; }_x000D_
.boxChild{ _x000D_
  margin:600px 0 300px; _x000D_
  width: 40px;_x000D_
  height:40px;_x000D_
  background:green;_x000D_
}
_x000D_
<button>Scroll to element</button>_x000D_
<div class='box'>_x000D_
  <div class='boxChild'></div>_x000D_
</div>
_x000D_
_x000D_
_x000D_

Method 2 - Using Element.scrollIntoView:

Note that browser support isn't great for this one

_x000D_
_x000D_
var targetElm = document.querySelector('.boxChild'),  // reference to scroll target_x000D_
    button = document.querySelector('button');        // button that triggers the scroll_x000D_
  _x000D_
// bind "click" event to a button _x000D_
button.addEventListener('click', function(){_x000D_
   targetElm.scrollIntoView()_x000D_
})
_x000D_
.box {_x000D_
  width: 80%;_x000D_
  border: 2px dashed;_x000D_
  height: 180px;_x000D_
  overflow: auto;_x000D_
  scroll-behavior: smooth; /* <-- for smooth scroll */_x000D_
}_x000D_
_x000D_
.boxChild {_x000D_
  margin: 600px 0 300px;_x000D_
  width: 40px;_x000D_
  height: 40px;_x000D_
  background: green;_x000D_
}
_x000D_
<button>Scroll to element</button>_x000D_
<div class='box'>_x000D_
  <div class='boxChild'></div>_x000D_
</div>
_x000D_
_x000D_
_x000D_

Method 3 - Using CSS scroll-behavior:

_x000D_
_x000D_
.box {_x000D_
  width: 80%;_x000D_
  border: 2px dashed;_x000D_
  height: 180px;_x000D_
  overflow-y: scroll;_x000D_
  scroll-behavior: smooth; /* <--- */_x000D_
}_x000D_
_x000D_
#boxChild {_x000D_
  margin: 600px 0 300px;_x000D_
  width: 40px;_x000D_
  height: 40px;_x000D_
  background: green;_x000D_
}
_x000D_
<a href='#boxChild'>Scroll to element</a>_x000D_
<div class='box'>_x000D_
  <div id='boxChild'></div>_x000D_
</div>
_x000D_
_x000D_
_x000D_


Code should be:

var divElem = document.getElementById('scrolling_div');
var chElem = document.getElementById('element_within_div');
var topPos = divElem.offsetTop;
divElem.scrollTop = topPos - chElem.offsetTop;

You want to scroll the difference between child top position and div's top position.

Get access to child elements using:

var divElem = document.getElementById('scrolling_div'); 
var numChildren = divElem.childNodes.length;

and so on....


Native JS, Cross Browser, Smooth Scroll (Update 2020)

Setting ScrollTop does give the desired result but the scroll is very abrupt. Using jquery to have smooth scroll was not an option. So here's a native way to get the job done that supports all major browsers. Reference - caniuse

// get the "Div" inside which you wish to scroll (i.e. the container element)
const El = document.getElementById('xyz');

// Lets say you wish to scroll by 100px, 
El.scrollTo({top: 100, behavior: 'smooth'});

// If you wish to scroll until the end of the container
El.scrollTo({top: El.scrollHeight, behavior: 'smooth'});

That's it!


And here's a working snippet for the doubtful -

_x000D_
_x000D_
document.getElementById('btn').addEventListener('click', e => {
  e.preventDefault();
  // smooth scroll
  document.getElementById('container').scrollTo({top: 175, behavior: 'smooth'});
});
_x000D_
/* just some styling for you to ignore */
.scrollContainer {
  overflow-y: auto;
  max-height: 100px;
  position: relative;
  border: 1px solid red;
  width: 120px;
}

body {
  padding: 10px;
}

.box {
  margin: 5px;
  background-color: yellow;
  height: 25px;
  display: flex;
  align-items: center;
  justify-content: center;
}

#goose {
  background-color: lime;
}
_x000D_
<!-- Dummy html to be ignored -->
<div id="container" class="scrollContainer">
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div id="goose" class="box">goose</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
  <div class="box">duck</div>
</div>

<button id="btn">goose</button>
_x000D_
_x000D_
_x000D_

Update: As you can perceive in the comments, it seems that Element.scrollTo() is not supported in IE11. So if you don't care about IE11 (you really shouldn't), feel free to use this in all your projects. Note that support exists for Edge! So you're not really leaving your Edge/Windows users behind ;)

Reference


given you have a div element you need to scroll inside, try this piece of code

document.querySelector('div').scroll(x,y)

this works with me inside a div with a scroll, this should work with you in case you pointed the mouse over this element and then tried to scroll down or up. If it manually works, it should work too


browser does scrolling automatically to an element that gets focus, so what you can also do it to wrap the element that you need to be scrolled to into <a>...</a> and then when you need scroll just set the focus on that a


Here's a simple pure JavaScript solution that works for a target Number (value for scrollTop), target DOM element, or some special String cases:

/**
 * target - target to scroll to (DOM element, scrollTop Number, 'top', or 'bottom'
 * containerEl - DOM element for the container with scrollbars
 */
var scrollToTarget = function(target, containerEl) {
    // Moved up here for readability:
    var isElement = target && target.nodeType === 1,
        isNumber = Object.prototype.toString.call(target) === '[object Number]';

    if (isElement) {
        containerEl.scrollTop = target.offsetTop;
    } else if (isNumber) {
        containerEl.scrollTop = target;
    } else if (target === 'bottom') {
        containerEl.scrollTop = containerEl.scrollHeight - containerEl.offsetHeight;
    } else if (target === 'top') {
        containerEl.scrollTop = 0;
    }
};

And here are some examples of usage:

// Scroll to the top
var scrollableDiv = document.getElementById('scrollable_div');
scrollToTarget('top', scrollableDiv);

or

// Scroll to 200px from the top
var scrollableDiv = document.getElementById('scrollable_div');
scrollToTarget(200, scrollableDiv);

or

// Scroll to targetElement
var scrollableDiv = document.getElementById('scrollable_div');
var targetElement= document.getElementById('target_element');
scrollToTarget(targetElement, scrollableDiv);

This is what has finally served me

/** Set parent scroll to show element
 * @param element {object} The HTML object to show
 * @param parent {object} The HTML object where the element is shown  */
var scrollToView = function(element, parent) {
    //Algorithm: Accumulate the height of the previous elements and add half the height of the parent
    var offsetAccumulator = 0;
    parent = $(parent);
    parent.children().each(function() {
        if(this == element) {
            return false; //brake each loop
        }
        offsetAccumulator += $(this).innerHeight();
    });
    parent.scrollTop(offsetAccumulator - parent.innerHeight()/2);
}

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to scroll

How to window.scrollTo() with a smooth effect Angular 2 Scroll to bottom (Chat style) Scroll to the top of the page after render in react.js Get div's offsetTop positions in React RecyclerView - How to smooth scroll to top of item on a certain position? Detecting scroll direction How to disable RecyclerView scrolling? How can I scroll a div to be visible in ReactJS? Make a nav bar stick Disable Scrolling on Body