Yapışkan kenar çubuğu: aşağı kaydırırken en alta, yukarı kaydırırken yukarı yap


94

Yapışkan kenar çubuğu sorunuma bir çözüm bulmak için bir süredir arıyordum. Nasıl davranmasını istediğime dair belirli bir fikrim var; Etkili bir şekilde, aşağı kaydırdığınızda aşağıya yapışmasını istiyorum ve sonra yukarı kaydırdığınız anda akıcı bir hareketle (zıplamadan) yukarıya yapışmasını istiyorum. Neyi başarmaya çalıştığıma dair bir örnek bulamıyorum, bu yüzden konuyu daha net göstereceğini umduğum bir görüntü yarattım:

Yapışkan kenar çubuğu: aşağı kaydırırken en alta, yukarı kaydırırken yukarı yap

  1. Kenar çubuğu başlığın altında bulunur.
  2. Siz aşağı kaydırdıkça kenar çubuğu sayfanın içeriği ile aynı seviyede kalır, böylece hem kenar çubuğunda hem de içerikte gezinebilirsiniz.
  3. Kenar çubuğunun alt kısmına ulaşın, kenar çubuğu görüntü alanının altına yapışır (çoğu eklenti yalnızca üste yapışmaya izin verir, bazıları aşağıya yapışmaya izin verenler her ikisine de izin vermez).
  4. Alta ulaşın, kenar çubuğu altbilginin üzerinde oturur.
  5. Siz yukarı kaydırdıkça, kenar çubuğu içerikle aynı seviyede kalır, böylece içerikte ve kenar çubuğunda tekrar kaydırabilirsiniz.
  6. Kenar çubuğunun üst kısmına ulaşınca, kenar çubuğu görünüm alanının üstüne yapışır.
  7. En üste ulaşın ve kenar çubuğu başlığın altına geri oturur.

Umarım bu yeterli bilgidir. Bu soru için sıfırladığım eklentileri / komut dosyalarını test etmek için bir jsfiddle oluşturdum: http://jsfiddle.net/jslucas/yr9gV/2/ .

Yanıtlar:


25

Çok güzel ve gösterişli bir görüntüye +1 .

Bunun eski bir soru olduğunu biliyorum, ancak sizin tarafınızdan forum.jquery.com'da yayınlanan aynı soruyu ve orada (@ tucker973 tarafından) bir yanıt buldum , bunu yapmak için güzel bir kitaplık önerdim ve burada paylaşmak istedim.

Bu denir yapışkan kiti ile @leafo

Burada hazırladığım çok basit bir örneğin kodu ve sonucu görmek için çalışan bir demo var.

Tabii ki, tüm krediler eklentinin yaratıcısına gidiyor, ben sadece bu örneği burada göstermek için yaptım. Senin peşinde olduğun sonucu elde etmem gerekiyor ve bu eklentiyi çok kullanışlı buldum.


Bu küçük eklentiyi önerdiğiniz gibi kullanıyorum, ancak üste yapıştırıldıktan sonra genişlik değişiyor. Nasıl değiştirmeyebilirim?
vijayrana

Merhaba @gmo! Aynı şeyi arıyorum, ancak kaydırma çubuğu görüntü alanından daha uzun olduğunda çalışmıyor (yukarı kaydırmada üstte kalmıyor) ...
Igor Laszlo

13

Harika grafik için teşekkürler. Ben de bu zorluğa bir çözüm arıyordum!

Maalesef, burada yayınlanan diğer cevap, kenar çubuğunda sorunsuz bir şekilde geri dönme yeteneğini şart koşan 5 numaralı gereksinimi ele almıyor.

Tüm gereksinimleri yerine getiren bir keman oluşturdum: http://jsfiddle.net/bN4qu/5/

Uygulanması gereken temel mantık şudur:

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

Keman içinde hedef elemanı hareket ettirmek için CSS3 dönüşümü kullanıyorum, bu yüzden örneğin IE <9'da çalışmayacak. Mantık, ancak farklı bir yaklaşım kullanmak için sağlamdır.

Ayrıca, yapışkan kenar çubuğunun gradyan arka planı olacak şekilde kemanınızı değiştirdim. Bu, doğru davranışın sergilendiğini göstermeye yardımcı olur.

Umarım bu birisi için yararlıdır!


2
Cevap arayanlar için, Travis'in yazdığı bu şimdiye kadar bulduğum en kusursuz olanı. Teşekkürler dostum.
marcovega

Harika bir girişim, temelde bunu düşürdüğümde işe yaradı, ki bu diğer eklentiler için söyleyebileceğimden daha fazlası :) Performans büyük bir darbe aldı, ancak bence bu, herhangi bir yerel olmayan yapışkan uygulamada verilmiş.
jClark

Bu mükemmel bir başlangıç ​​noktasıydı! Ben sarılmış $.cssbir işlevi requestAnimationFrameve vue gibi modern önyüzü çerçeveler kullanım için bir imha / unbind fonksiyonu eklendi / reaksiyon gösterirler. Bundan sonra performans kesinlikle sorun değil!
Christophe Marois

@Cristophe Marois jsfiddle ile ilgili bir örnek verebilir misiniz lütfen?
DuArme

teşekkürler, ancak bu kod görüntü alanından (görüntü
alanının

12

İşte bunun nasıl uygulanacağına dair bir örnek:

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/25ultyE/

Bu, tüm senaryolarda beklendiği gibi çalışır ve IE'de de iyi desteklenir.



@Anoop Naik - aradığım neredeyse iyi ... yapışkan kit, görüntü alanından daha uzun kenar çubuklarında çalışmıyor, sizinki çalışıyor. Bununla birlikte, tam tersini istiyorum: aşağı kaydırdığımda, üstte kalıyor ve yukarı kaydırırken, altta kalıyor ... lütfen bana bir kemanla o küçük değişim için yardım edebilir misin?
Igor Laszlo

1
@IgorLaszlo tabii, biraz zaman ver, bir süre sonra seni güncelleyeceğim ...
Anoop Naik

Bu aynı zamanda benim sorunumu da açıklıyor: "Konum: yapışkan olan öğe" sıkışmış "sa ve görüntü alanından daha uzunsa, içeriğini yalnızca kabın altına kaydırdıktan sonra görebilirsiniz. "Sıkışmış" öğe kaydırılırsa harika olur belgeyle birlikte ve durduğunda, alt kenarına ulaştığında. Kullanıcı geri kaydırırsa, aynı şey tekrar olur, ancak tersi olur. " - aynı sorunu yaşayan başka bir kişi tarafından yazılmıştır ( stackoverflow.com/questions/47618271/… )
Igor Laszlo

@Anoop Naik! Çabanız için teşekkürler ama lütfen izin verin, sorunumu çözmek için Sticky jquery eklentisini buldum: abouolia.github.io/sticky-sidebar Tekrar teşekkürler!
Igor Laszlo

0

Ben de aynı şeyi arıyordum. Görünüşe göre, sadece grafikle benzer bir soru bulmak için bazı belirsiz terimleri aramam gerekiyordu. Tam olarak aradığım şey olduğu ortaya çıktı. Herhangi bir eklenti bulamadığım için kendim yapmaya karar verdim. Umarım birisi bunu görür ve iyileştirir.

İşte kullandığım hızlı ve kirli bir html örneği.

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

İşte yaptığım jQuery:

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

    });
}

Bazı notlar:

  • .rectbtfad, kenar çubuğumdaki en alttaki öğe
  • # Masthead'imin yüksekliğini kullanıyorum çünkü bu yapışkan bir başlık, dolayısıyla telafi etmesi gerekiyor
  • Duyarlı bir tasarım kullandığım ve bunun daha küçük ekranlarda etkinleştirilmesini istemediğim için col-2 float için bir kontrol var

Bunu biraz daha rafine edebilen biri varsa bu harika olur.


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

Çalışma Örneği: https://jsfiddle.net/L7xoopst/6/


biraz açıklama eklediniz mi?
HaveNoDisplayName

Yapışkan öğenin içindeki yüksekliği güncellerseniz, bunun bazı sorunları vardır
Callam

0

Wordpress deposunda WP Sticky Sidebar olarak bilinen nispeten bilinmeyen bir eklenti var. Eklenti tam olarak istediğiniz şeyi yapar (Yapışkan kenar çubuğu: aşağı kaydırırken aşağıya, yukarı kaydırırken yukarı yapıştır) WP Sticky Kenar Çubuğu Wordpress deposu Bağlantısı: https://wordpress.org/plugins/mystickysidebar/


Bilgi için teşekkürler! Mükemmel çalıştı. Eklenti özellikli görsel için davranış illüstrasyon grafiğinin aynı olması komik :)
Oksana Romaniv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.