-->

How to scroll to an element inside a div?

2019-01-01 15:26发布

问题:

I have a scrolled div and I want to have a link 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 that

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

回答1:

You need to get the top offset of the element you\'d like to scroll into view, relative to its parent (the scrolling div container):

var myElement = document.getElementById(\'element_within_div\');
var topPos = myElement.offsetTop;

The variable topPos is now set to the distance between the top of the scrolling div and the element you wish to have visible (in pixels).

Now we tell the div to scroll to that position using scrollTop:

document.getElementById(\'scrolling_div\').scrollTop = topPos;

If you\'re using the prototype JS framework, you\'d do the same thing like this:

var posArray = $(\'element_within_div\').positionedOffset();
$(\'scrolling_div\').scrollTop = posArray[1];

Again, this will scroll the div so that the element you wish to see is exactly at the top (or if that\'s not possible, scrolled as far down as it can so it\'s visible).



回答2:

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;
  }


回答3:

Method 1 - Smooth scrolling to an element inside an element

var box = document.querySelector(\'.box\'),
    targetElm = document.querySelector(\'.boxChild\'); // <-- Scroll to here within \".box\"

document.querySelector(\'button\').addEventListener(\'click\', function(){
   scrollToElm( box, targetElm , 600 );   
});


/////////////

function scrollToElm(container, elm, duration){
  var pos = getRelativePos(elm);
  scrollTo( container, pos.top , 2);  // duration in seconds
}

function getRelativePos(elm){
  var pPos = elm.parentNode.getBoundingClientRect(), // parent pos
      cPos = elm.getBoundingClientRect(), // target pos
      pos = {};

  pos.top    = cPos.top    - pPos.top + elm.parentNode.scrollTop,
  pos.right  = cPos.right  - pPos.right,
  pos.bottom = cPos.bottom - pPos.bottom,
  pos.left   = cPos.left   - pPos.left;

  return pos;
}
    
function scrollTo(element, to, duration, onDone) {
    var start = element.scrollTop,
        change = to - start,
        startTime = performance.now(),
        val, now, elapsed, t;

    function animateScroll(){
        now = performance.now();
        elapsed = (now - startTime)/1000;
        t = (elapsed/duration);

        element.scrollTop = start + change * easeInOutQuad(t);

        if( t < 1 )
            window.requestAnimationFrame(animateScroll);
        else
            onDone && onDone();
    };

    animateScroll();
}

function easeInOutQuad(t){ return t<.5 ? 2*t*t : -1+(4-2*t)*t };
.box{ width:80%; border:2px dashed; height:180px; overflow:auto; }
.boxChild{ 
  margin:600px 0 300px; 
  width: 40px;
  height:40px;
  background:green;
}
<button>Scroll to element</button>
<div class=\'box\'>
  <div class=\'boxChild\'></div>
</div>

Method 2 - Using Element.scrollIntoView:

Note that browser support isn\'t great for this one

var box = document.querySelector(\'.box\'),
    targetElm = document.querySelector(\'.boxChild\');

document.querySelector(\'button\').addEventListener(\'click\', function(){
   targetElm.scrollIntoView(); 
});
.box {
  width: 80%;
  border: 2px dashed;
  height: 180px;
  overflow: auto;
  scroll-behavior: smooth; /* <-- for smooth scroll */
}

.boxChild {
  margin: 600px 0 300px;
  width: 40px;
  height: 40px;
  background: green;
}
<button>Scroll to element</button>
<div class=\'box\'>
  <div class=\'boxChild\'></div>
</div>

Method 3 - Using CSS scroll-behavior:

.box {
  width: 80%;
  border: 2px dashed;
  height: 180px;
  overflow-y: scroll;
  scroll-behavior: smooth; /* <--- */
}

#boxChild {
  margin: 600px 0 300px;
  width: 40px;
  height: 40px;
  background: green;
}
<a href=\'#boxChild\'>Scroll to element</a>
<div class=\'box\'>
  <div id=\'boxChild\'></div>
</div>



回答4:

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



回答5:

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

function scrollIfNeeded(element, container) {
  if (element.offsetTop < container.scrollTop) {
    container.scrollTop = element.offsetTop;
  } else {
    const offsetBottom = element.offsetTop + element.offsetHeight;
    const scrollBottom = container.scrollTop + container.offsetHeight;
    if (offsetBottom > scrollBottom) {
      container.scrollTop = offsetBottom - container.offsetHeight;
    }
  }
}

document.getElementById(\'btn\').addEventListener(\'click\', ev => {
  ev.preventDefault();
  scrollIfNeeded(document.getElementById(\'goose\'), document.getElementById(\'container\'));
});
.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;
}
<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\">scroll to goose</button>



回答6:

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.



回答7:

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);


回答8:

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);
    }
}


回答9:

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);
}


回答10:

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\");
    }
});