Klebrige Seitenleiste: Bleiben Sie beim Scrollen nach unten und beim Scrollen nach oben oben


91

Ich habe seit einiger Zeit nach einer Lösung für mein Problem mit der klebrigen Seitenleiste gesucht. Ich habe eine konkrete Vorstellung davon, wie es sich verhalten soll. effektiv möchte ich, dass es beim Scrollen nach unten bleibt, und sobald Sie wieder nach oben scrollen, möchte ich, dass es in einer fließenden Bewegung (kein Springen) oben bleibt. Ich kann kein Beispiel dafür finden, was ich erreichen möchte, deshalb habe ich ein Bild erstellt, von dem ich hoffe, dass es den Punkt klarer verdeutlicht:

Klebrige Seitenleiste: Bleiben Sie beim Scrollen nach unten und beim Scrollen nach oben oben

  1. Die Seitenleiste befindet sich unter der Kopfzeile.
  2. Während Sie nach unten scrollen, bleibt die Seitenleiste auf gleicher Höhe mit dem Inhalt der Seite, sodass Sie sowohl durch die Seitenleiste als auch durch den Inhalt scrollen können.
  3. Erreichen Sie die Unterseite der Seitenleiste, die Seitenleiste bleibt am unteren Rand des Ansichtsfensters hängen (die meisten Plugins erlauben nur das Festhalten an der Oberseite, einige, die das Festhalten an der Unterseite ermöglichen, erlauben nicht beide).
  4. Erreichen Sie den unteren Rand, die Seitenleiste befindet sich über der Fußzeile.
  5. Während Sie nach oben scrollen, bleibt die Seitenleiste auf gleicher Höhe mit dem Inhalt, sodass Sie erneut durch den Inhalt und die Seitenleiste scrollen können.
  6. Erreichen Sie die Oberseite der Seitenleiste, die Seitenleiste bleibt oben im Ansichtsfenster.
  7. Erreichen Sie die Oberseite und die Seitenleiste befindet sich wieder unter der Kopfzeile.

Ich hoffe das sind genug Informationen. Ich habe eine jsfiddle erstellt, um alle Plugins / Skripte zu testen, die ich für diese Frage zurückgesetzt habe: http://jsfiddle.net/jslucas/yr9gV/2/ .

Antworten:


25

+1 auf das sehr schöne und illustrative Bild.

Ich weiß, dass es eine alte Frage ist, aber ich habe beiläufig dieselbe Frage gefunden, die Sie in forum.jquery.com gestellt haben, und eine Antwort dort (von @ tucker973) , eine nette Bibliothek vorgeschlagen, um dies zu machen, und wollte sie hier teilen.

Es heißt Sticky-Kit von @leafo

Hier haben Sie den Code eines sehr einfachen Beispiels, das ich vorbereitet habe, und eine funktionierende Demo, um das Ergebnis zu sehen.

Natürlich gehen alle Credits an den Ersteller des Plugins. Ich habe dieses Beispiel nur gemacht, um es hier zu zeigen. Ich muss das gleiche Ergebnis erzielen, nach dem Sie gesucht haben, und fand dieses Plugin sehr nützlich.


Ich benutze dieses kleine Plugin, wie Sie vorschlagen, aber die Breite ändert sich, nachdem es oben haftet. Wie kann ich es unverändert machen?
Vijayrana

Hallo @gmo! Ich suche das Gleiche, aber es funktioniert nicht (bleibt beim Scrollen nicht oben), wenn die Bildlaufleiste länger als das Ansichtsfenster ist ...
Igor Laszlo

13

Danke für die tolle Grafik. Ich suchte auch nach einer Lösung für diese Herausforderung!

Leider geht die andere hier veröffentlichte Antwort nicht auf Anforderung Nr. 5 ein, die die Möglichkeit vorsieht, reibungslos durch die Seitenleiste zurückzuscrollen.

Ich habe eine Geige erstellt, die alle Anforderungen implementiert: http://jsfiddle.net/bN4qu/5/

Die Kernlogik, die implementiert werden muss, ist:

If scrolling up OR the element is shorter than viewport Then
  Set top of element to top of viewport If scrolled above top of element
If scrolling down then
  Set bottom of element at bottom of viewport If scrolled past bottom of element

In der Geige verwende ich die CSS3-Transformation, um das Zielelement zu verschieben, sodass es in z. B. IE <9 nicht funktioniert. Die Logik ist jedoch solide, um einen anderen Ansatz zu verwenden.

Außerdem habe ich Ihre Geige so geändert, dass die klebrige Seitenleiste einen Hintergrund mit Farbverlauf hat. Dies hilft zu zeigen, dass das richtige Verhalten gezeigt wird.

Ich hoffe das ist nützlich für jemanden!


2
Für jeden, der nach einer Antwort sucht, ist diese von Travis die makelloseste, die ich bisher gefunden habe. Danke, Mann.
Marcovega

Ein großartiger Versuch, es hat im Grunde nur funktioniert, als ich dies eingestellt habe, was mehr ist, als ich für andere Plugins sagen könnte :) Die Leistung hat einen großen Erfolg gehabt, aber ich denke, das ist bei jeder nicht-nativen Sticky-Implementierung so ziemlich selbstverständlich.
jClark

Dies war ein ausgezeichneter Ausgangspunkt! Ich habe die $.cssFunktion in a verpackt requestAnimationFrameund eine Destroy / Unbind-Funktion zur Verwendung in modernen Frontend-Frameworks wie vue / react hinzugefügt. Leistung ist danach absolut kein Thema mehr!
Christophe Marois

@Cristophe Marois Kannst du bitte ein Beispiel für jsfiddle geben?
DuArme

danke, aber dieser Code funktioniert nicht für kleine Seitenleisten, die kürzer als das Ansichtsfenster (Höhe des Ansichtsfensters) sind
Seyed Abbas Seyedi

12

Hier ist ein Beispiel für die Implementierung:

JavaScript:

$(function() {

var $window = $(window);
var lastScrollTop = $window.scrollTop();
var wasScrollingDown = true;

var $sidebar = $("#sidebar");
if ($sidebar.length > 0) {

    var initialSidebarTop = $sidebar.position().top;

    $window.scroll(function(event) {

        var windowHeight = $window.height();
        var sidebarHeight = $sidebar.outerHeight();

        var scrollTop = $window.scrollTop();
        var scrollBottom = scrollTop + windowHeight;

        var sidebarTop = $sidebar.position().top;
        var sidebarBottom = sidebarTop + sidebarHeight;

        var heightDelta = Math.abs(windowHeight - sidebarHeight);
        var scrollDelta = lastScrollTop - scrollTop;

        var isScrollingDown = (scrollTop > lastScrollTop);
        var isWindowLarger = (windowHeight > sidebarHeight);

        if ((isWindowLarger && scrollTop > initialSidebarTop) || (!isWindowLarger && scrollTop > initialSidebarTop + heightDelta)) {
            $sidebar.addClass('fixed');
        } else if (!isScrollingDown && scrollTop <= initialSidebarTop) {
            $sidebar.removeClass('fixed');
        }

        var dragBottomDown = (sidebarBottom <= scrollBottom && isScrollingDown);
        var dragTopUp = (sidebarTop >= scrollTop && !isScrollingDown);

        if (dragBottomDown) {
            if (isWindowLarger) {
                $sidebar.css('top', 0);
            } else {
                $sidebar.css('top', -heightDelta);
            }
        } else if (dragTopUp) {
            $sidebar.css('top', 0);
        } else if ($sidebar.hasClass('fixed')) {
            var currentTop = parseInt($sidebar.css('top'), 10);

            var minTop = -heightDelta;
            var scrolledTop = currentTop + scrollDelta;

            var isPageAtBottom = (scrollTop + windowHeight >= $(document).height());
            var newTop = (isPageAtBottom) ? minTop : scrolledTop;

            $sidebar.css('top', newTop);
        }

        lastScrollTop = scrollTop;
        wasScrollingDown = isScrollingDown;
    });
}
});

CSS:

#sidebar {
  width: 180px;
  padding: 10px;
  background: red;
  float: right;
}

.fixed {
  position: fixed;
  right: 50%;
  margin-right: -50%;
}

Demo: http://jsfiddle.net/ryanmaxwell/25QaE/

Dies funktioniert in allen Szenarien wie erwartet und wird auch im IE gut unterstützt.


Sehen Sie diese Antwort und erklären Sie stackoverflow.com/questions/28428327/…
theinlwin

@Anoop Naik - das ist fast gut, wonach ich suche ... Sticky-Kit funktioniert nicht für Seitenleisten, die länger als das Ansichtsfenster sind, Ihre funktioniert. Ich möchte jedoch das Gegenteil: Wenn ich nach unten scrolle, klebt es oben und beim Scrollen nach oben klebt es unten ... können Sie mir bitte bei dieser kleinen Änderung in einer Geige helfen?
Igor Laszlo

1
@IgorLaszlo sicher, gib mir etwas Zeit, wird dich in einiger Zeit aktualisieren ...
Anoop Naik

Dies erklärt auch mein Problem: "Wenn ein Element mit Position: sticky" stecken bleibt "und länger als das Ansichtsfenster ist, können Sie seinen Inhalt erst sehen, nachdem Sie zum Boden des Containers gescrollt haben. Es wäre cool, wenn das" steckengebliebene "Element gescrollt wäre mit dem Dokument und gestoppt, sobald es seinen unteren Rand erreicht. Wenn der Benutzer zurück scrollen würde, würde das gleiche wieder passieren, aber in umgekehrter Reihenfolge. " - geschrieben von einer anderen Person, die das gleiche Problem hat ( stackoverflow.com/questions/47618271/… )
Igor Laszlo

@ Anoop Naik! Vielen Dank für Ihre Mühe, aber lassen Sie es bitte, ich habe das Sticky JQuery Plugin gefunden, um mein Problem zu lösen: abouolia.github.io/sticky-sidebar Nochmals vielen Dank!
Igor Laszlo

0

Ich suchte genau das Gleiche. Anscheinend musste ich nach obskuren Begriffen suchen, um eine ähnliche Frage mit der Grafik zu finden. Es stellt sich heraus, dass es genau das ist, wonach ich gesucht habe. Ich konnte keine Plugins finden und habe beschlossen, es selbst zu machen. Hoffentlich wird jemand dies sehen und verfeinern.

Hier ist ein schnelles und schmutziges Beispiel-HTML, das ich verwende.

<div id="main">
    <div class="col-1">
    </div>
    <div class="col-2">
        <div class="side-wrapper">
            sidebar content
        </div>
    </div>
</div>

Hier ist die jQuery, die ich gemacht habe:

var lastScrollPos = $(window).scrollTop();
var originalPos = $('.side-wrapper').offset().top;
if ($('.col-2').css('float') != 'none') {
    $(window).scroll(function(){
        var rectbtfadPos = $('.rectbtfad').offset().top + $('.rectbtfad').height();
        // scroll up direction
        if ( lastScrollPos > $(window).scrollTop() ) {
            // unstick if scrolling the opposite direction so content will scroll with user
            if ($('.side-wrapper').css('position') == 'fixed') {
                $('.side-wrapper').css({
                    'position': 'absolute',
                    'top': $('.side-wrapper').offset().top + 'px',
                    'bottom': 'auto'
                });
            } 
            // if has reached the original position, return to relative positioning
            if ( ($(window).scrollTop() + $('#masthead').height()) < originalPos ) {
                $('.side-wrapper').css({
                    'position': 'relative',
                    'top': 'auto',
                    'bottom': 'auto'
                });
            } 
            // sticky to top if scroll past top of sidebar
            else if ( ($(window).scrollTop() + $('#masthead').height()) < $('.side-wrapper').offset().top && $('.side-wrapper').css('position') == 'absolute' ) {
                $('.side-wrapper').css({
                    'position': 'fixed',
                    'top': 15 + $('#masthead').height() + 'px', // padding to compensate for sticky header
                    'bottom': 'auto'
                });
            }
        } 
        // scroll down
        else {
            // unstick if scrolling the opposite direction so content will scroll with user
            if ($('.side-wrapper').css('position') == 'fixed') {
                $('.side-wrapper').css({
                    'position': 'absolute',
                    'top': $('.side-wrapper').offset().top + 'px',
                    'bottom': 'auto'
                });
            } 
            // check if rectbtfad (bottom most element) has reached the bottom
            if ( ($(window).scrollTop() + $(window).height()) > rectbtfadPos && $('.side-wrapper').css('position') != 'fixed' ) {
                $('.side-wrapper').css({
                    'width': $('.col-2').width(),
                    'position': 'fixed',
                    'bottom': '0',
                    'top': 'auto'
                });
            }
        }
        // set last scroll position to determine if scrolling up or down
        lastScrollPos = $(window).scrollTop();

    });
}

Einige Notizen:

  • .rectbtfad ist das unterste Element in meiner Seitenleiste
  • Ich verwende die Höhe meines #masthead, da es sich um einen klebrigen Header handelt, der dies kompensieren muss
  • Es gibt eine Überprüfung auf col-2 float, da ich ein responsives Design verwende und nicht möchte, dass dies auf kleineren Bildschirmen aktiviert wird

Wenn jemand dies ein bisschen weiter verfeinern kann, wäre das großartig.


0
function fixMe(id) {
    var e = $(id);
    var lastScrollTop = 0;
    var firstOffset = e.offset().top;
    var lastA = e.offset().top;
    var isFixed = false;
    $(window).scroll(function(event){
        if (isFixed) {
            return;
        }
        var a = e.offset().top;
        var b = e.height();
        var c = $(window).height();
        var d = $(window).scrollTop();
        if (b <= c - a) {
            e.css({position: "fixed"});
            isFixed = true;
            return;
        }           
        if (d > lastScrollTop){ // scroll down
            if (e.css("position") != "fixed" && c + d >= a + b) {
                e.css({position: "fixed", bottom: 0, top: "auto"});
            }
            if (a - d >= firstOffset) {
                e.css({position: "absolute", bottom: "auto", top: lastA});
            }
        } else { // scroll up
            if (a - d >= firstOffset) {
                if (e.css("position") != "fixed") {
                    e.css({position: "fixed", bottom: "auto", top: firstOffset});
                }
            } else {
                if (e.css("position") != "absolute") {
                    e.css({position: "absolute", bottom: "auto", top: lastA});
                }               
            }
        }
        lastScrollTop = d;
        lastA = a;
    });
}

fixMe("#stick");

Arbeitsbeispiel: https://jsfiddle.net/L7xoopst/6/


ein bisschen Erklärung hinzufügen?
HaveNoDisplayName

Wenn Sie die Höhe innerhalb des klebrigen Elements aktualisieren,
treten

0

Es gibt ein relativ unbekanntes Plugin im Wordpress-Repository, das als WP Sticky Sidebar bekannt ist. Das Plugin macht genau das, was Sie wollten (Sticky Sidebar: Bleiben Sie beim Scrollen nach unten, beim Scrollen nach oben oben) WP Sticky Sidebar Wordpress-Repository Link: https://wordpress.org/plugins/mystickysidebar/


Danke für die Information! Hat perfekt funktioniert. Es ist lustig, dass die Verhaltensillustrationsgrafik für das Plugin-Bild gleich ist :)
Oksana Romaniv
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.