Sidebar lengket: tetap di bawah saat menggulir ke bawah, ke atas saat menggulir ke atas

94

Saya telah mencari beberapa waktu sekarang untuk solusi untuk masalah bilah sisi lengket saya. Saya memiliki gagasan khusus tentang bagaimana saya ingin ia bertindak; secara efektif, saya ingin papan itu menempel di bagian bawah saat Anda menggulir ke bawah, dan segera setelah Anda menggulir kembali ke atas, saya ingin papan itu tetap di atas, dalam gerakan yang mengalir (tidak ada lompatan). Saya tidak dapat menemukan contoh dari apa yang saya coba capai, jadi saya telah membuat gambar yang saya harap akan mengilustrasikan poin dengan lebih jelas:

Sidebar lengket: tetap di bawah saat menggulir ke bawah, ke atas saat menggulir ke atas

  1. Sidebar berada di bawah header.
  2. Saat Anda menggulir ke bawah, bilah sisi tetap sejajar dengan konten halaman sehingga Anda dapat menggulir melalui bilah sisi dan konten.
  3. Jangkau bagian bawah sidebar, sidebar menempel ke bagian bawah viewport (kebanyakan plugin hanya memungkinkan untuk menempel di atas, beberapa yang memungkinkan untuk menempel ke bawah tidak memungkinkan untuk keduanya).
  4. Capai bagian bawah, sidebar berada di atas footer.
  5. Saat Anda menggulir kembali ke atas, bilah sisi tetap sejajar dengan konten sehingga Anda dapat menggulir kembali konten dan bilah sisi.
  6. Jangkau bagian atas bar samping, bar samping menempel ke bagian atas viewport.
  7. Capai bagian atas dan sidebar berada kembali di bawah header.

Saya harap ini cukup informasi. Saya telah membuat jsfiddle untuk menguji plugin / skrip apa pun, yang telah saya setel ulang untuk pertanyaan ini: http://jsfiddle.net/jslucas/yr9gV/2/ .

andbamnan
sumber

Jawaban:

26

+1 untuk gambar yang sangat bagus dan ilustratif.

Saya tahu ini pertanyaan lama, tetapi saya dengan santai menemukan pertanyaan yang sama yang diposting oleh Anda di forum.jquery.com dan satu jawaban di sana (oleh @ tucker973) , menyarankan satu perpustakaan bagus untuk membuat ini dan ingin membagikannya di sini.

Ini disebut sticky-kit oleh @leafo

Di sini Anda memiliki kode contoh yang sangat mendasar yang saya siapkan dan demo yang berfungsi untuk melihat hasilnya.

Tentu saja, semua kredit diberikan kepada pembuat plugin, saya hanya membuat contoh ini untuk ditampilkan di sini. Saya perlu mencapai hasil yang sama dengan yang Anda kejar dan merasa plugin ini sangat berguna.

gmo
sumber
Saya menggunakan plugin kecil ini seperti yang Anda sarankan, tetapi lebar berubah setelah menempel di bagian atas. Bagaimana saya bisa membuatnya tidak berubah?
vijayrana
Hai @gmo! Saya mencari hal yang sama tetapi tidak berhasil (tidak menempel di atas pada gulir ke atas) ketika bilah gulir lebih panjang dari viewport ...
Igor Laszlo
13

Terima kasih untuk grafik yang bagus. Saya juga mencari solusi untuk tantangan ini!

Sayangnya, jawaban lain yang diposting di sini tidak memenuhi persyaratan # 5 yang menetapkan kemampuan untuk menggulir kembali bilah sisi dengan lancar.

Saya membuat biola yang menerapkan semua persyaratan: http://jsfiddle.net/bN4qu/5/

Logika inti yang perlu diimplementasikan adalah:

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

Di biola saya menggunakan transformasi CSS3 untuk memindahkan elemen target, jadi itu tidak akan berfungsi di misalnya IE <9. Logikanya masuk akal untuk menggunakan pendekatan yang berbeda.

Juga, saya memodifikasi biola Anda sehingga bilah sisi yang lengket memiliki latar belakang gradien. Ini membantu untuk menunjukkan bahwa perilaku yang tepat sedang ditampilkan.

Saya harap ini bermanfaat bagi seseorang!

Travis Kriplean
sumber
2
Bagi siapa pun yang mencari jawaban, yang ini dari Travis adalah yang paling sempurna yang saya temukan sejauh ini. Terima kasih sobat.
marcovega
Upaya hebat, pada dasarnya hanya berfungsi ketika saya memasukkan ini, yang lebih dari yang dapat saya katakan untuk plugin lain :) Performa mengalami pukulan besar, tetapi saya pikir itu cukup banyak diberikan dengan implementasi sticky non-native.
jClark
Ini adalah titik awal yang sangat bagus! Saya membungkus $.cssfungsi dalam a requestAnimationFramedan menambahkan fungsi penghancuran / pelepasan untuk digunakan dalam kerangka kerja frontend modern seperti vue / react. Performa sama sekali bukan masalah setelah itu!
Christophe Marois
@Cristophe Marois bisakah Anda memberikan contoh tentang jsfiddle?
DuArme
terima kasih, tetapi kode ini tidak berfungsi untuk bilah sisi kecil yang lebih pendek dari area pandang (ketinggian area pandang)
Seyed Abbas Seyedi
12

Berikut adalah contoh bagaimana menerapkan ini:

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/

Ini berfungsi seperti yang diharapkan di semua skenario dan juga didukung dengan baik di IE.

Anoop Naik
sumber
lihat jawaban ini dan jelaskan stackoverflow.com/questions/28428327/…
theinlwin
@Anoop Naik - hampir bagus apa yang saya cari ... sticky-kit tidak bekerja untuk sidebar yang lebih panjang dari viewport, milik anda berfungsi. Namun saya ingin yang sebaliknya: ketika saya menggulir ke bawah, itu menempel di atas, dan dalam menggulir ke atas, itu menempel di bawah ... bisakah Anda membantu saya dengan perubahan kecil di biola?
Igor Laszlo
1
@IgorLaszlo yakin, beri saya waktu, akan memperbarui Anda dalam beberapa waktu ...
Anoop Naik
Ini juga menjelaskan masalah saya: "Ketika elemen dengan position: sticky" macet "dan lebih panjang dari viewport, Anda hanya dapat melihat isinya setelah Anda menggulir ke bawah penampung. Alangkah baiknya, jika elemen" macet "di-scroll dengan dokumen dan berhenti, setelah mencapai tepi bawahnya. Jika pengguna men-scroll ke belakang, hal yang sama akan terjadi lagi, tetapi sebaliknya. " - ditulis oleh orang lain yang memiliki masalah yang sama ( stackoverflow.com/questions/47618271/… )
Igor Laszlo
@Anoop Naik! Terima kasih atas usaha Anda tetapi biarkan saja, saya menemukan plugin jquery Sticky untuk menyelesaikan masalah saya: abouolia.github.io/sticky-sidebar Terima kasih lagi!
Igor Laszlo
0

Saya mencari hal yang persis sama. Rupanya saya perlu mencari beberapa istilah yang tidak jelas hanya untuk menemukan pertanyaan yang mirip dengan grafik. Ternyata itulah yang saya cari. Saya tidak dapat menemukan plugin apa pun, jadi saya memutuskan untuk membuatnya sendiri. Semoga seseorang akan melihat ini dan memperbaikinya.

Ini contoh html cepat dan kotor yang saya gunakan.

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

Inilah jQuery yang saya buat:

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

    });
}

Beberapa catatan:

  • .rectbtfad adalah elemen paling bawah di sidebar saya
  • Saya menggunakan ketinggian #masthead saya karena ini adalah header yang lengket sehingga perlu mengimbanginya
  • Ada tanda centang untuk col-2 float karena saya menggunakan desain responsif dan tidak ingin ini diaktifkan di layar yang lebih kecil

Jika ada yang bisa menyempurnakan ini sedikit lebih banyak, itu akan bagus.

callmeforsox
sumber
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");

Contoh Kerja: https://jsfiddle.net/L7xoopst/6/

SezginOnline
sumber
tambahkan sedikit penjelasan?
HaveNoDisplayName
Jika Anda memperbarui tinggi dalam item melekat ini memiliki beberapa masalah
Callam
0

Ada plugin yang relatif tidak dikenal di repositori Wordpress yang dikenal sebagai WP Sticky Sidebar. Plugin melakukan apa yang Anda inginkan (Sticky sidebar: menempel ke bawah saat menggulir ke bawah, atas saat menggulir ke atas) WP Sticky Sidebar Wordpress repositori Tautan: https://wordpress.org/plugins/mystickysidebar/

Manju Talluri
sumber
Terimakasih atas infonya! Bekerja dengan sempurna. Lucu sekali bahwa grafik ilustrasi perilaku sama untuk gambar fitur plugin :)
Oksana Romaniv