ScrollIntoView () haciendo que toda la página se mueva

110

Estoy usando ScrollIntoView () para desplazar el elemento resaltado en una lista a la vista. Cuando me desplazo hacia abajo, ScrollIntoView (falso) funciona perfectamente. Pero cuando me desplazo hacia arriba, ScrollIntoView (verdadero) hace que toda la página se mueva un poco, lo que creo que está previsto. ¿Hay alguna manera de evitar que toda la página se mueva cuando se usa ScrollIntoView (verdadero)?

Aquí está la estructura de mi página:

#listOfDivs {
  position:fixed;
  top:100px;
  width: 300px;
  height: 300px;
  overflow-y: scroll;
}

<div="container">
    <div="content"> 
         <div id="listOfDivs"> 
             <div id="item1"> </div>
             <div id="item2"> </div>
             <div id="itemn"> </div>
         </div>
    </div>
</div>

listOfDivs proviene de una llamada ajax. Usando safari móvil.

¡Gracias por su ayuda de antemano!

Estoy aquí
fuente
1
¿Puede proporcionar un JSFiddle para que podamos ver exactamente cuál es el problema?
Robert Koritnik

Respuestas:

115

Podrías usar en scrollToplugar de scrollIntoView():

var target = document.getElementById("target");
target.parentNode.scrollTop = target.offsetTop;

jsFiddle: http://jsfiddle.net/LEqjm/

Si hay más de un elemento desplazable por el que desea desplazarse, deberá cambiar el scrollTopde cada uno de forma individual, según la offsetTops de los elementos intermedios. Esto debería darle un control detallado para evitar el problema que está teniendo.

EDITAR: offsetTop no es necesariamente relativo al elemento padre, es relativo al primer antepasado posicionado. Si el elemento principal no está posicionado (relativo, absoluto o fijo), es posible que deba cambiar la segunda línea a:

target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop;
Brillante
fuente
3
FYI, esto solo funciona cuando el padre está en la parte superior de la página. Probablemente deberías hacerlotarget.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil
2
offsetTop es relativo al padre posicionado más cercano, por lo que si el nodo padre tiene position: relative, entonces no debe restar su desplazamiento. Pero tienes razón para la mayoría de los casos.
Brilliand
2
Aquí hay un violín js: jsfiddle.net/LEqjm/258 que muestra también el comportamiento incorrecto de ScrollIntoView.
Rafi
1
@Brilliand gracias por la idea sobre position: relativeen prent div: realmente soluciona el problema
Alex Zhukovskiy
Funciona en Chrome, pero se desplaza un poco más en IE, lo que oculta el contenido del texto en la parte superior. Cualquier solución @Phil, gracias de antemano
Soniya
121

Arreglado con:

element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })

ver: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

jfrohn
fuente
1
Gracias esto funcionó. No entendí el uso de block y sus valores cuando lo leí. Ahora que resolvió un problema, sé lo que está haciendo
Pavan
3
¿Qué significa "más cercano"? EDITAR: Encontré una respuesta aquí: stackoverflow.com/a/48635751/628418
Sammi
Esto resolvió mi problema. He estado viendo que esto sucede en nuestra aplicación web durante algún tiempo, pero ha sido difícil bloquear la reproducción. Después de agregar una nueva característica, ocurría cada vez y pude rastrearla hasta esta llamada, a la que le faltaba el block : 'nearest'parámetro.
roskelld
Si tan solo definieran lo que significan los valores del bloque ... inicio y más cercano ... todo es prueba y error.
Bae
Funciona con Chrome, pero no con Edge para mí.
Michael
13
var el = document.querySelector("yourElement");
window.scroll({top: el.offsetTop, behavior: 'smooth'});
momento bipolar
fuente
o puede usartop: el['offsetTop']
Junior Mayhé
Esto funciona mejor para mí. Pero todavía tiene un pequeño error en Firefox, a veces se detiene en el camino hacia el elemento. Fino en borde y cromado.
Marcos
9

Yo también tuve este problema y pasé muchas horas tratando de solucionarlo. Espero que mi resolución pueda ayudar a algunas personas.

Mi solución terminó siendo:

  • Para Chrome: cambiando .scrollIntoView()a .scrollIntoView({block: 'nearest'})(gracias a @jfrohn).
  • Para Firefox: aplique overflow: -moz-hidden-unscrollable;en el elemento contenedor que cambia.
  • No probado en otros navegadores.
paddotk
fuente
8

Juega con scrollIntoViewIfNeeded()... asegúrate de que sea compatible con el navegador.

Jesco
fuente
1
No sabía que eso era una cosa. Hay un polyfill
mpen
En el documento, se menciona que no es estándar pero funciona bien. ¿Deberíamos usarlo?
Shyam Kumar
8

Agregué una forma de mostrar el comportamiento inadecuado de ScrollIntoView: http://jsfiddle.net/LEqjm/258/ [debería ser un comentario pero no tengo suficiente reputación]

$("ul").click(function() {
    var target = document.getElementById("target");
if ($('#scrollTop').attr('checked')) {
    target.parentNode.scrollTop = target.offsetTop;    
} else {
        target.scrollIntoView(!0);
}
});
Michal Tsadok
fuente
7
No es una pregunta de jQuery.
seangates
6

El complemento jQuery scrollintoview()aumenta la usabilidad

En lugar de la implementación de DOM predeterminada, puede usar un complemento que anime el movimiento y no tenga efectos no deseados. Esta es la forma más sencilla de usarlo con valores predeterminados:

$("yourTargetLiSelector").scrollintoview();

De todos modos, diríjase a esta publicación de blog donde puede leer todos los detalles y eventualmente lo llevará al código fuente de GitHub del complemento.

Este complemento busca automáticamente el elemento antepasado desplazable más cercano y lo desplaza para que el elemento seleccionado esté dentro de su puerto de vista visible. Si el elemento ya está en el puerto de visualización, por supuesto, no hace nada.

Robert Koritnik
fuente
19
@Brilliand: Eso es cierto, por supuesto, pero eso no significa que no lo estén usando o que sean reacios a usarlo. Todo lo que hago es ofrecer una alternativa. Depende de OP decidir si ese es un camino que tomarían o no. Quizás nunca consideraron usar jQuery en primer lugar.
Robert Koritnik
Ese OP no mencionó específicamente a jQuery es completamente irrelevante: la respuesta de @ RobertKoritnik me sirvió perfectamente.
Dave Land
1
Por cierto, Bing muestra su ejemplo de código en los resultados de búsqueda para "evitar que el elemento ancestro se desplace con scrollintoview". :-)
Dave Land
2

Usando la idea de Brilliant, aquí hay una solución que solo se desplaza (verticalmente) si el elemento NO está visible actualmente. La idea es que el cuadro delimitador de la ventana gráfica y el elemento se muestren en el espacio de coordenadas de la ventana del navegador. Compruebe si está visible y, si no, desplácese por la distancia requerida para que el elemento se muestre en la parte superior o inferior de la ventana gráfica.

    function ensure_visible(element_id)
    {
        // adjust these two to match your HTML hierarchy
        var element_to_show  = document.getElementById(element_id);
        var scrolling_parent = element_to_show.parentElement;

        var top = parseInt(scrolling_parent.getBoundingClientRect().top);
        var bot = parseInt(scrolling_parent.getBoundingClientRect().bottom);

        var now_top = parseInt(element_to_show.getBoundingClientRect().top);
        var now_bot = parseInt(element_to_show.getBoundingClientRect().bottom);

        // console.log("Element: "+now_top+";"+(now_bot)+" Viewport:"+top+";"+(bot) );

        var scroll_by = 0;
        if(now_top < top)
            scroll_by = -(top - now_top);
        else if(now_bot > bot)
            scroll_by = now_bot - bot;
        if(scroll_by != 0)
        {
            scrolling_parent.scrollTop += scroll_by; // tr.offsetTop;
        }
    }
KungPhoo
fuente
2

Añadiendo más información para @Jescopublicar.

  • Element.scrollIntoViewIfNeeded() non-standard WebKit methodpara los navegadores Chrome, Opera, Safari.
    Si el elemento ya se encuentra dentro del área visible de la ventana del navegador, no se realiza ningún desplazamiento .
  • Element.scrollIntoView() El método desplaza el elemento en el que se llama al área visible de la ventana del navegador.

Pruebe el siguiente código en el mozilla.org scrollIntoView()enlace. Publicar para identificar el navegador

var xpath = '//*[@id="Notes"]';
ScrollToElement(xpath);

function ScrollToElement(xpath) {
    var ele = $x(xpath)[0];
    console.log( ele );

    var isChrome = !!window.chrome && (!!window.chrome.webstore || !!window.chrome.runtime);
    if (isChrome) { // Chrome
        ele.scrollIntoViewIfNeeded();
    } else {
        var inlineCenter = { behavior: 'smooth', block: 'center', inline: 'start' };
        ele.scrollIntoView(inlineCenter);
    }
}
Yash
fuente
2

en mi contexto, empujaría la barra de herramientas adhesiva fuera de la pantalla, o ingresaría junto a un botón fabuloso con absoluto.

usando el resuelto más cercano.

const element = this.element.nativeElement;
const table = element.querySelector('.table-container');
table.scrollIntoView({
  behavior: 'smooth', block: 'nearest'
});
Búsqueda Gui
fuente
1

Tuve el mismo problema, lo solucioné eliminando el transform:translateYCSS que coloqué en el footerde la página.

yael kfir
fuente