ScrollIntoView () bewirkt, dass die gesamte Seite verschoben wird

109

Ich verwende ScrollIntoView (), um das markierte Element in einer Liste in die Ansicht zu scrollen. Wenn ich nach unten scrolle, funktioniert ScrollIntoView (false) perfekt. Wenn ich jedoch nach oben scrolle, bewirkt ScrollIntoView (true), dass sich die gesamte Seite ein wenig bewegt, was meiner Meinung nach beabsichtigt ist. Gibt es eine Möglichkeit, das Verschieben der gesamten Seite zu vermeiden, wenn ScrollIntoView (true) verwendet wird?

Hier ist die Struktur meiner Seite -

#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 kommt von einem Ajax-Aufruf. Mobile Safari nutzen.

Danke im Vorraus für deine Hilfe!

Ich bin da
quelle
1
Können Sie eine JSFiddle bereitstellen, damit wir genau sehen können, wo das Problem liegt?
Robert Koritnik

Antworten:

115

Sie könnten scrollTopanstelle von verwenden scrollIntoView():

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

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

Wenn es mehr als ein scrollbares Element gibt, das Sie scrollen möchten, müssen Sie das Element scrollTopeinzeln ändern , basierend auf den offsetTops der dazwischenliegenden Elemente. Dies sollte Ihnen die feinkörnige Kontrolle geben, um das Problem zu vermeiden, das Sie haben.

BEARBEITEN: offsetTop ist nicht unbedingt relativ zum übergeordneten Element, sondern relativ zum zuerst positionierten Vorfahren. Wenn das übergeordnete Element nicht positioniert ist (relativ, absolut oder fest), müssen Sie möglicherweise die zweite Zeile in Folgendes ändern:

target.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop;
Brilliand
quelle
3
Zu Ihrer Information, dies funktioniert nur, wenn sich das übergeordnete Element oben auf der Seite befindet. Sie sollten es wahrscheinlich schaffentarget.parentNode.scrollTop = target.offsetTop - target.parentNode.offsetTop
Phil
2
offsetTop ist relativ zum nächstgelegenen positionierten übergeordneten Element. Wenn der übergeordnete Knoten dies hat position: relative, sollten Sie seinen Versatz nicht subtrahieren. Aber Sie haben in den meisten Fällen Recht.
Brilliand
2
Hier ist eine js-Geige: jsfiddle.net/LEqjm/258 , die auch das falsche Verhalten von ScrollIntoView zeigt.
Rafi
1
@ Brilliand danke für die Idee über position: relativeauf prent div: es behebt wirklich das Problem
Alex Zhukovskiy
Es funktioniert mit Chrome, aber es scrollt ein bisschen mehr im IE, wodurch der Textinhalt von oben ausgeblendet wird. Jede Lösung @Phil, danke im Voraus
Soniya
116

Es wurde behoben mit:

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

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

jfrohn
quelle
1
Danke das hat funktioniert. Ich habe die Verwendung von Block und seinen Werten beim Lesen nicht verstanden. Jetzt, da es ein Problem gelöst hat, weiß ich, was es tut
Pavan
3
Was bedeutet "am nächsten"? EDIT: Hier eine Antwort gefunden: stackoverflow.com/a/48635751/628418
Sammi
Dies löste mein Problem. Ich habe dies schon seit einiger Zeit in unserer Web-App gesehen, aber es war schwierig, den Repro dafür zu sperren. Nachdem ich eine neue Funktion hinzugefügt hatte, trat sie jedes Mal auf und ich konnte sie auf diesen Aufruf block : 'nearest'zurückführen , bei dem der Parameter fehlte .
Roskelld
Wenn sie nur definieren würden, was die Blockwerte bedeuten ... Start und nächste ... ist alles Versuch und Irrtum.
Bae
Funktioniert mit Chrome, aber nicht mit Edge für mich.
Michael
12
var el = document.querySelector("yourElement");
window.scroll({top: el.offsetTop, behavior: 'smooth'});
dipole_moment
quelle
oder Sie können verwendentop: el['offsetTop']
Junior Mayhé
8

Spielen Sie mit scrollIntoViewIfNeeded()... stellen Sie sicher, dass es vom Browser unterstützt wird.

Jesco
quelle
1
Ich wusste nicht, dass das eine Sache ist. Es gibt eine
Polyfüllung
In dem Dokument wird dort erwähnt, dass es nicht Standard ist, aber es funktioniert gut. sollen wir es benutzen?
Shyam Kumar
8

Ich habe eine Möglichkeit hinzugefügt, das wichtige Verhalten von ScrollIntoView anzuzeigen - http://jsfiddle.net/LEqjm/258/ [Es sollte ein Kommentar sein, aber ich habe nicht genug Ruf]

$("ul").click(function() {
    var target = document.getElementById("target");
if ($('#scrollTop').attr('checked')) {
    target.parentNode.scrollTop = target.offsetTop;    
} else {
        target.scrollIntoView(!0);
}
});
Michal Tsadok
quelle
7
Keine jQuery-Frage.
Seangates
8

Ich hatte auch dieses Problem und verbrachte viele Stunden damit, damit umzugehen. Ich hoffe, meine Entschließung kann einigen Menschen noch helfen.

Mein Fix war:

  • Für Chrome: Wechsel .scrollIntoView()zu .scrollIntoView({block: 'nearest'})(danke an @jfrohn).
  • Für Firefox: overflow: -moz-hidden-unscrollable;Auf das verschobene Containerelement anwenden .
  • Nicht in anderen Browsern getestet.
Paddotk
quelle
6

Das jQuery-Plugin scrollintoview()erhöht die Benutzerfreundlichkeit

Anstelle der Standard-DOM-Implementierung können Sie ein Plugin verwenden, das Bewegungen animiert und keine unerwünschten Effekte hat. Hier ist die einfachste Möglichkeit, es mit Standardeinstellungen zu verwenden:

$("yourTargetLiSelector").scrollintoview();

Gehen Sie auf jeden Fall zu diesem Blog-Beitrag, in dem Sie alle Details lesen und schließlich zum GitHub-Quellcode des Plugins gelangen.

Dieses Plugin sucht automatisch nach dem nächsten scrollbaren Vorfahrenelement und scrollt es so, dass sich das ausgewählte Element in seinem sichtbaren Ansichtsfenster befindet. Befindet sich das Element bereits im Ansichtsfenster, führt es natürlich nichts aus.

Robert Koritnik
quelle
19
@Brilliand: Das ist natürlich wahr, aber das bedeutet nicht, dass sie es nicht benutzen oder es nur ungern benutzen. Ich biete nur eine Alternative an. Es liegt an OP zu entscheiden, ob dies ein Weg ist, den sie einschlagen würden oder nicht. Vielleicht haben sie nie daran gedacht, jQuery überhaupt zu verwenden.
Robert Koritnik
Dass OP jQuery nicht ausdrücklich erwähnt hat, ist völlig irrelevant: @ RobertKoritniks Antwort hat mir perfekt gedient.
Dave Land
1
Übrigens zeigt Bing Ihr Codebeispiel in den Suchergebnissen für "Verhindern, dass Vorfahrenelemente mit scrollintoview scrollen". :-)
Dave Land
2

Nach der Idee von Brilliant ist hier eine Lösung, die nur (vertikal) einen Bildlauf durchführt, wenn das Element derzeit NICHT sichtbar ist. Die Idee ist, den Begrenzungsrahmen des Ansichtsfensters und das Element zu erhalten, die im Koordinatenraum des Browserfensters angezeigt werden sollen. Überprüfen Sie, ob es sichtbar ist, und scrollen Sie, falls nicht, um den erforderlichen Abstand, damit das Element oben oder unten im Ansichtsfenster angezeigt wird.

    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
quelle
2

Hinzufügen weiterer Informationen zum @JescoPosten.

  • Element.scrollIntoViewIfNeeded() non-standard WebKit methodfür Chrome-, Opera- und Safari-Browser.
    Befindet sich das Element bereits im sichtbaren Bereich des Browserfensters, findet kein Bildlauf statt .
  • Element.scrollIntoView() Die Methode scrollt das Element, für das es aufgerufen wird, in den sichtbaren Bereich des Browserfensters.

Versuchen Sie den folgenden Code im mozilla.org scrollIntoView()Link. Beitrag zur Identifizierung des Browsers

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
quelle
2

In meinem Kontext würde er die klebrige Symbolleiste vom Bildschirm schieben oder neben einer fabelhaften Schaltfläche mit Absolut eingeben.

mit dem nächsten gelöst.

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

Ich hatte das gleiche Problem, ich habe es behoben, indem transform:translateYich das CSS entfernt habe, das ich auf footerder Seite platziert habe.

Yael Kfir
quelle