Come scorrere fino a un elemento all'interno di un div?


170

Ho uno scorrimento dive voglio avere un link quando faccio clic su di esso costringerà questo diva scorrere per visualizzare un elemento all'interno. Ho scritto il suo JavasSript in questo modo:

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

ma questo scorre tutta la pagina mentre scorre la divstessa. Come risolverlo?

Voglio dirlo così

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

Scrolltop non restituisce sempre un valore utilizzabile. Tendo a usare a SetTimeoutnella $(document).ready({})funzione e impostare focus()l'elemento a cui si desidera scorrere. Funziona per me
DerpyNerd il

Risposte:


340

Devi ottenere l'offset superiore dell'elemento che desideri scorrere in vista, rispetto al suo genitore (il contenitore div a scorrimento):

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

La variabile topPos è ora impostata sulla distanza tra la parte superiore del div a scorrimento e l'elemento che si desidera sia visibile (in pixel).

Ora diciamo al div di scorrere fino a quella posizione usando scrollTop:

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

Se stai usando il prototipo di framework JS, faresti la stessa cosa in questo modo:

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

Ancora una volta, questo farà scorrere il div in modo che l'elemento che desideri vedere sia esattamente in alto (o se ciò non è possibile, fatto scorrere il più in basso possibile in modo che sia visibile).


9
Questo è stato davvero utile! Se si desidera impostare lo scorrimento più volte, è necessario compensare dalla posizione di scorrimento corrente. Ecco come l'ho fatto in jQuery: $ ('# scrolling_div'). ScrollTop ($ ('# scrolling_div'). ScrollTop () + $ ('# element_within_div'). Position (). Top);
Sarà il

3
Attenzione che la richiesta myElement.offsetTopattiverà il reflow (layout thrashing) che potrebbe essere un collo di bottiglia delle prestazioni
Kestutis

27
Ricorda di impostare il genitore a scorrimento con css: position: relativealtrimenti passerai molto tempo a eseguire il debug come ho appena fatto.
saveario

2
Ho dovuto impostare la overflow-yproprietà su scrollper l'elemento parent ( scrolling_div), altrimenti non funzionava. Il valore css predefinito per la overflowproprietà è autoe anche se rende anche possibile lo scorrimento manuale, il codice js non funzionerebbe (nemmeno con {psition: relative}..)
Evgenia Manolova,

2
Funziona ancora nel 2017. Ulteriori informazioni: .offsetTop potrebbe restituire 0. Quindi devi fare riferimento a un elemento padre e riprovare. L'ho fatto per i tag h4allora divpoi articletag e solo articlelavorato per me.
Fenio,

66

Dovresti trovare la posizione dell'elemento nel DIV che desideri scorrere e impostare la proprietà scrollTop.

divElem.scrollTop = 0;

Aggiornamento :

Codice di esempio per spostarsi verso l'alto o verso il basso

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

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

3
voglio farlo scorrere, per vederlo non scorrere con un certo valore
Amr Elgarhy,

39

Metodo 1: scorrimento uniforme fino a un elemento all'interno di un elemento

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>

Metodo 2 - Utilizzo di Element.scrollIntoView :

Si noti che il supporto del browser non è eccezionale per questo

var targetElm = document.querySelector('.boxChild'),  // reference to scroll target
    button = document.querySelector('button');        // button that triggers the scroll
  
// bind "click" event to a button 
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>

Metodo 3 - Utilizzo del comportamento di scorrimento CSS :

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


1
Si noti che il comportamento di scorrimento non è supportato in IE / Edge / Safari
scatta il

1
@sheats - dice esattamente che nel collegamento alla documentazione MDN che avevo inserito in caratteri di grandi dimensioni. Anche se non funziona con quei browser, non significa che non dovresti usarlo. Non esiste una "regola", tutto deve comportarsi allo stesso modo su tutti i browser. Se i browser moderni possono fare magie, lascia che facciano magie.
vsync,

Questo post riguarda lo scorrimento dell'intero documento piuttosto che un elemento scorrevole.

@ DoMiNeLa10 - È un presupposto. OP potrebbe aver fornito un esempio arbitrario che intendeva illustrare il suo problema. Inoltre, l'OP non è la preoccupazione principale, ma piuttosto le persone provenienti dai motori di ricerca alla ricerca di una soluzione salutare, e molto probabilmente rispondendo specificamente alle esigenze dei PO non li aiuteranno, e l'obiettivo di questo sito Web è quello di creare risposte solide che possano aiutare altrettante il più possibile. La mia risposta fornisce entrambi .
vsync,

12

Per scorrere un elemento in vista di un div, solo se necessario, è possibile utilizzare questa scrollIfNeededfunzione:

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>


1
Questo è stato davvero utile. Ho faticato un po 'perché avevo perso la posizione: parente sul container. È stato fondamentale!
brohr,

11

Il codice dovrebbe essere:

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

Si desidera scorrere la differenza tra la posizione superiore del figlio e la posizione superiore del div.

Ottieni l'accesso agli elementi figlio utilizzando:

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

e così via....


1
La seconda riga non dovrebbe effettivamente leggere var chElem = document.getElementById('element_within_div');e la terza riga leggere var topPos = divElem.offsetTop;?
Jay

7

Se si utilizza jQuery, è possibile scorrere con un'animazione usando quanto segue:

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

L'animazione è facoltativa: puoi anche prendere il valore scrollTop calcolato sopra e inserirlo direttamente nella proprietà scrollTop del contenitore .


5

JS nativo, Cross Browser, Smooth Scroll (Aggiornamento 2020)

L'impostazione ScrollTopfornisce il risultato desiderato ma lo scorrimento è molto brusco. L'uso jquerydi uno scorrimento uniforme non era un'opzione. Quindi ecco un modo nativo per portare a termine il lavoro che supporta tutti i principali browser. Riferimento - 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'});

Questo è tutto!


Ed ecco uno snippet funzionante per i dubbiosi -

document.getElementById('btn').addEventListener('click', e => {
  e.preventDefault();
  // smooth scroll
  document.getElementById('container').scrollTo({top: 175, behavior: 'smooth'});
});
/* 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;
}
<!-- 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>

Aggiornamento: come puoi percepire nei commenti, sembra che Element.scrollTo()non sia supportato in IE11. Quindi, se non ti interessa IE11 (davvero non dovresti), sentiti libero di usarlo in tutti i tuoi progetti. Si noti che esiste supporto per Edge! Quindi non lascerai davvero indietro gli utenti Edge / Windows;)

Riferimento


1
scrollTo()può essere supportato in tutti i principali browser per gli Windowoggetti ma non è supportato in IE o Edge per gli elementi.
Tim Down

Secondo caniuse , è supportato in IE11 e Edge. Non ho testato personalmente su questi browser, ma sembra essere supportato.
Niket Pathak,

1
Non è window.scrollTocosì Element.scrollTo. Prova questo in Edge, ad esempio, e controlla la console: codepen.io/timdown/pen/abzVEMB
Tim Down

hai ragione. IE11 non è supportato. Tuttavia Edge v76 (rif) e versioni successive sembrano essere supportati
Niket Pathak il

2

Ci sono due fatti:

1) Component scrollIntoView non è supportato da Safari.

2) JS framework jQuery può fare il lavoro in questo modo:

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

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

1

Ecco una semplice soluzione JavaScript pura che funziona con un numero di destinazione (valore per scrollTop), un elemento DOM di destinazione o alcuni casi String speciali:

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

Ed ecco alcuni esempi di utilizzo:

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

o

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

o

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

1

Un altro esempio di utilizzo di jQuery e 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");
    }
});

0

Scorrimento animato dall'utente

Ecco un esempio di come scorrere programmaticamente un <div>orizzontale, senza JQuery . Per scorrere verticalmente, sostituiresti invece le scritture JavaScript scrollLeftcon scrollTop.

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

Ringraziamo Dux .


Scorrimento animato automatico

Inoltre, qui ci sono funzioni per scorrere <div>completamente a sinistra e a destra. L'unica cosa che cambiamo qui è che controlliamo se l'estensione completa dello scorrimento è stata utilizzata prima di effettuare una chiamata ricorsiva per scorrere nuovamente.

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

0

Questo è ciò che mi ha finalmente servito

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

0

il browser fa scorrere automaticamente fino a un elemento che ottiene lo stato attivo, quindi cosa puoi fare anche per avvolgere l'elemento su cui devi scorrere <a>...</a>e quindi quando hai bisogno di scorrere basta impostare lo stato attivo su quelloa


0

Dopo aver selezionato l'elemento basta usare la scrollIntoViewfunzione con l'opzione qui sotto:

const option = {
  top: 0, // number,
  left: 0, // number,
  behavior: 'auto', // auto or smooth 
    // - auto for one jump motion and smooth for animated motion -
};

Quindi la risposta per questo post è:

const el = document.getElementById('id-name');
el.scrollIntoView({
  top: 0,
  left: 0,
  behavior: 'auto',
});

0

dato che hai un elemento div che devi scorrere all'interno, prova questo pezzo di codice

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

questo funziona con me all'interno di un div con una pergamena, dovrebbe funzionare con te nel caso in cui hai puntato il mouse su questo elemento e poi hai provato a scorrere verso il basso o verso l'alto. Se funziona manualmente, dovrebbe funzionare anche

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.