¿Cómo desplazarse a un elemento dentro de un div?

170

Tengo un desplazamiento divy quiero tener un enlace cuando hago clic en él, lo obligará diva desplazarse para ver un elemento en su interior. Escribí su JavasSript así:

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

pero esto desplaza toda la página mientras desplaza la divpropia. ¿Cómo arreglar eso?

Quiero decirlo asi

MyContainerDiv.getElementById(chr).scrollIntoView(true);
Amr Elgarhy
fuente
Scrolltop no siempre devuelve un valor utilizable. Tiendo a usar a SetTimeouten la $(document).ready({})función y establecer focus()el elemento al que desea desplazarse. Funciona para mí
DerpyNerd

Respuestas:

340

Debe obtener el desplazamiento superior del elemento que desea desplazar a la vista, en relación con su elemento primario (el contenedor div de desplazamiento):

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

La variable topPos ahora se establece en la distancia entre la parte superior del div de desplazamiento y el elemento que desea tener visible (en píxeles).

Ahora le decimos al div que se desplace a esa posición usando scrollTop:

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

Si está utilizando el prototipo de marco JS, haría lo mismo de esta manera:

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

Nuevamente, esto desplazará el div para que el elemento que desea ver esté exactamente en la parte superior (o si eso no es posible, desplácese lo más abajo posible para que sea visible).

Brian Barrett
fuente
9
¡Esto fue realmente útil! Si desea establecer el desplazamiento varias veces, debe compensarlo con su ubicación de desplazamiento actual. Así es como lo hice en jQuery: $ ('# scrolling_div'). ScrollTop ($ ('# scrolling_div'). ScrollTop () + $ ('# element_within_div'). Position (). Top);
Será el
3
Tenga en cuenta que la solicitud myElement.offsetTopprovocará un reflujo (cambio de diseño) que podría ser un cuello de botella en el rendimiento
Kestutis
27
Recuerde configurar el padre de desplazamiento con css: de lo position: relativecontrario, pasará mucho tiempo depurando como acabo de hacer.
savedario
2
Tuve que establecer la overflow-ypropiedad scrollpara el elemento padre ( scrolling_div), de lo contrario no estaba funcionando. El valor predeterminado de CSS para la overflowpropiedad es autoy, aunque también hace posible el desplazamiento manual, el código js no funcionaría (ni siquiera con {psition: relative}...)
Evgenia Manolova
2
Todavía funciona en 2017. Información adicional: .offsetTop podría devolver 0. Luego, debe consultar un elemento principal e intentar nuevamente. Lo hice para las etiquetas h4y divluego las articleetiquetas y solo articlefuncionó para mí.
Fenio
66

Tendría que encontrar la posición del elemento en el DIV al que desea desplazarse y establecer la propiedad scrollTop.

divElem.scrollTop = 0;

Actualización :

Código de muestra para subir o bajar

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

  function move_down() {
    document.getElementById('divElem').scrollTop -= 10;
  }
Glennular
fuente
3
quiero ver que desplazarse, al ver que no desplazándose con un cierto valor
Amr Elgarhy
39

Método 1: desplazamiento suave a un elemento dentro de 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>

Método 2 - Usando Element.scrollIntoView :

Tenga en cuenta que el soporte del navegador no es excelente para este

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>

Método 3: uso del comportamiento de desplazamiento 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>

vsync
fuente
1
Tenga en cuenta que el comportamiento de desplazamiento no es compatible con IE / Edge / Safari
límite del
1
@sheats: dice exactamente eso en el enlace de documentación de MDN que había colocado en tamaño de fuente grande. Incluso si no funciona para esos navegadores, no significa que no deba usarlo. No existe una "regla": todo debe comportarse igual en todos los navegadores. Si los navegadores modernos pueden hacer magia, déjelos hacer magia.
vsync
Esta publicación se trata de desplazar todo el documento en lugar de un elemento desplazable.
@ DoMiNeLa10 - Eso es una suposición. OP podría haber proporcionado un ejemplo arbitrario que pretendía ilustrar su problema. Además, OP no es la principal preocupación, sino más bien personas que provienen de motores de búsqueda que buscan una solución saludable, y lo más probable es que responder específicamente a las necesidades de OP no los ayude, y el objetivo de este sitio web es crear respuestas sólidas que puedan ayudar a tantos como sea posible. Mi respuesta proporciona ambos .
vsync
12

Para desplazar un elemento a la vista de un div, solo si es necesario, puede usar esta scrollIfNeededfunción:

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>

mpen
fuente
1
Esto fue realmente útil. Luché un poco porque había perdido la posición: pariente en el contenedor. Eso fue crucial!
Brohr
11

El código debe ser:

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

Desea desplazar la diferencia entre la posición superior del niño y la posición superior del div.

Obtenga acceso a elementos secundarios utilizando:

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

y así....

pgp
fuente
1
¿No debería leer la segunda línea var chElem = document.getElementById('element_within_div');y leer la tercera línea var topPos = divElem.offsetTop;?
jayp
7

Si está utilizando jQuery, puede desplazarse con una animación usando lo siguiente:

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

La animación es opcional: también puede tomar el valor scrollTop calculado anteriormente y ponerlo directamente en la propiedad scrollTop del contenedor .

dlauzon
fuente
5

Native JS, Cross Browser, Smooth Scroll (Actualización 2020)

La configuración ScrollTopda el resultado deseado, pero el desplazamiento es muy brusco. Usar jquerytener un desplazamiento suave no era una opción. Así que aquí hay una forma nativa de hacer el trabajo que admite todos los principales navegadores. Referencia - 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'});

¡Eso es!


Y aquí hay un fragmento de trabajo para los dudosos:

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>

Actualización: Como puede percibir en los comentarios, parece que Element.scrollTo()no es compatible con IE11. Entonces, si no le importa IE11 (realmente no debería), no dude en usarlo en todos sus proyectos. Tenga en cuenta que existe soporte para Edge! Entonces, realmente no estás dejando atrás a tus usuarios de Edge / Windows;)

Referencia

Niket Pathak
fuente
1
scrollTo()puede ser compatible con todos los principales navegadores para Windowobjetos, pero no es compatible con IE o Edge para elementos.
Tim Down
Según caniuse , es compatible con IE11 y Edge. No he probado personalmente en estos navegadores, pero parece ser compatible.
Niket Pathak
1
Eso window.scrollTono Element.scrollTo. Pruebe esto en Edge, por ejemplo, y verifique la consola: codepen.io/timdown/pen/abzVEMB
Tim Down
tienes razón. IE11 no es compatible. Sin embargo, Edge v76 (ref) y superior parece ser compatible
Niket Pathak
2

Hay dos hechos:

1) El componente scrollIntoView no es compatible con safari.

2) JS framework jQuery puede hacer el trabajo de esta manera:

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

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

Aquí hay una solución simple de JavaScript puro que funciona para un Número de destino (valor para scrollTop), un elemento DOM de destino o algunos casos especiales de Cadena:

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

Y aquí hay algunos ejemplos de uso:

// 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);
Pan comido
fuente
1

Otro ejemplo de uso de jQuery y 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");
    }
});
Hopefulee
fuente
0

Desplazamiento animado por el usuario

Aquí hay un ejemplo de cómo desplazarse mediante programación <div>horizontalmente, sin JQuery . Para desplazarse verticalmente, debería reemplazar las escrituras de JavaScript scrollLeftcon scrollTop, en su lugar.

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

Crédito a Dux .


Desplazamiento animado automático

Además, aquí hay funciones para desplazarse <div>completamente a la izquierda y a la derecha. Lo único que cambiamos aquí es que verificamos si se ha utilizado la extensión completa del desplazamiento antes de realizar una llamada recursiva para volver a desplazarse.

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);
    }
}
Mapsy
fuente
0

Esto es lo que finalmente me ha servido.

/** 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);
}
Iñigo Panera
fuente
0

el navegador se desplaza automáticamente a un elemento que obtiene el foco, por lo que también puede hacerlo para envolver el elemento al que necesita desplazarse <a>...</a>y luego, cuando necesite desplazarse, simplemente establezca el foco en esoa

Trident D'Gao
fuente
0

Después de seleccionar el elemento, simplemente use la scrollIntoViewfunción con la siguiente opción:

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

Entonces la respuesta para esta publicación es:

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

dado que tiene un elemento div que necesita para desplazarse dentro, pruebe este código

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

esto funciona conmigo dentro de un div con un desplazamiento, esto debería funcionar con usted en caso de que apunte el mouse sobre este elemento y luego intente desplazarse hacia abajo o hacia arriba. Si funciona manualmente, también debería funcionar

Amado Saladino
fuente