แถบด้านข้างเหนียว: ติดที่ด้านล่างเมื่อเลื่อนลงด้านบนเมื่อเลื่อนขึ้น


94

ตอนนี้ฉันกำลังมองหาวิธีแก้ปัญหาแถบด้านข้างที่เหนียว ฉันมีความคิดที่เฉพาะเจาะจงว่าฉันต้องการให้ดำเนินการอย่างไร อย่างมีประสิทธิภาพฉันต้องการให้มันติดอยู่ที่ด้านล่างเมื่อคุณเลื่อนลงจากนั้นทันทีที่คุณเลื่อนกลับขึ้นฉันต้องการให้มันติดอยู่ด้านบนในลักษณะที่ลื่นไหล (ไม่กระโดด) ฉันไม่สามารถหาตัวอย่างของสิ่งที่ฉันพยายามจะบรรลุได้ดังนั้นฉันจึงสร้างภาพที่ฉันหวังว่าจะอธิบายประเด็นให้ชัดเจนขึ้น:

แถบด้านข้างเหนียว: ติดที่ด้านล่างเมื่อเลื่อนลงด้านบนเมื่อเลื่อนขึ้น

  1. แถบด้านข้างอยู่ใต้ส่วนหัว
  2. เมื่อคุณเลื่อนลงแถบด้านข้างจะยังคงอยู่ในระดับเดียวกับเนื้อหาของเพจเพื่อให้คุณสามารถเลื่อนดูทั้งแถบด้านข้างและเนื้อหาได้
  3. ไปถึงด้านล่างสุดของแถบด้านข้างแถบด้านข้างจะติดที่ด้านล่างของวิวพอร์ต (ปลั๊กอินส่วนใหญ่อนุญาตให้ติดที่ด้านบนเท่านั้นบางส่วนที่อนุญาตให้ติดที่ด้านล่างไม่อนุญาตให้ใช้ทั้งสองอย่าง)
  4. ไปถึงด้านล่างแถบด้านข้างจะอยู่เหนือส่วนท้าย
  5. ในขณะที่คุณเลื่อนกลับขึ้นแถบด้านข้างจะอยู่ในระดับเดียวกับเนื้อหาเพื่อให้คุณสามารถเลื่อนดูเนื้อหาและแถบด้านข้างได้อีกครั้ง
  6. ไปถึงด้านบนสุดของแถบด้านข้างแถบด้านข้างจะติดที่ด้านบนสุดของวิวพอร์ต
  7. ไปถึงด้านบนและแถบด้านข้างจะอยู่ด้านล่างส่วนหัว

ฉันหวังว่านี่เป็นข้อมูลที่เพียงพอ ฉันได้สร้าง jsfiddle เพื่อทดสอบปลั๊กอิน / สคริปต์ใด ๆ ซึ่งฉันได้รีเซ็ตสำหรับคำถามนี้: http://jsfiddle.net/jslucas/yr9gV/2/ .

คำตอบ:


26

+1ให้กับภาพสวย ๆ น่ารัก ๆ

ฉันรู้ว่ามันเป็นคำถามเก่า แต่ฉันพบคำถามเดียวกันที่คุณโพสต์ไว้ในforum.jquery.comโดยบังเอิญและมีคำตอบหนึ่งคำตอบที่นั่น(โดย @ tucker973)แนะนำห้องสมุดที่ดีหนึ่งแห่งเพื่อสร้างสิ่งนี้และต้องการแบ่งปันที่นี่

เรียกว่าSticky-kitโดย@leafo

ที่นี่คุณมีรหัสของตัวอย่างพื้นฐานที่ฉันเตรียมไว้และการสาธิตที่ใช้งานได้เพื่อดูผลลัพธ์

แน่นอนว่าเครดิตทั้งหมดไปที่ผู้สร้างปลั๊กอินฉันทำแค่ตัวอย่างนี้เพื่อแสดงที่นี่ ฉันต้องการที่จะบรรลุผลลัพธ์เดียวกันกับที่คุณเป็นและพบว่าปลั๊กอินนี้มีประโยชน์มาก


ฉันใช้ปลั๊กอินขนาดเล็กนี้ตามที่คุณแนะนำ แต่ความกว้างจะเปลี่ยนไปหลังจากที่ติดอยู่ด้านบน ฉันจะทำให้มันไม่เปลี่ยนแปลงได้อย่างไร?
vijayrana

สวัสดี @gmo! ฉันกำลังมองหาสิ่งเดียวกัน แต่ไม่ได้ผล (ไม่ติดอยู่ด้านบนเมื่อเลื่อนขึ้น) เมื่อแถบเลื่อนยาวกว่าวิวพอร์ต ...
Igor Laszlo

13

ขอบคุณสำหรับภาพกราฟิกที่ยอดเยี่ยม ฉันกำลังมองหาวิธีแก้ปัญหาสำหรับความท้าทายนี้ด้วย!

น่าเสียดายที่คำตอบอื่น ๆ ที่โพสต์ไว้ที่นี่ไม่ได้ระบุข้อกำหนด # 5 ที่กำหนดความสามารถในการเลื่อนย้อนกลับผ่านแถบด้านข้างได้อย่างราบรื่น

ฉันสร้างซอที่ปฏิบัติตามข้อกำหนดทั้งหมด: http://jsfiddle.net/bN4qu/5/

ตรรกะหลักที่ต้องดำเนินการคือ:

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

ในซอฉันใช้การแปลง CSS3 เพื่อย้ายองค์ประกอบเป้าหมายไปรอบ ๆ ดังนั้นมันจะไม่ทำงานในเช่น IE <9 ตรรกะนั้นฟังดูดีแม้ว่าจะใช้วิธีการอื่น

นอกจากนี้ฉันแก้ไขซอของคุณเพื่อให้แถบด้านข้างเหนียวมีพื้นหลังไล่ระดับ สิ่งนี้ช่วยแสดงให้เห็นว่ามีการแสดงพฤติกรรมที่เหมาะสม

ฉันหวังว่านี่จะเป็นประโยชน์กับใครบางคน!


2
สำหรับทุกคนที่กำลังค้นหาคำตอบคำตอบนี้ของ Travis นั้นไร้ที่ติที่สุดที่ฉันเคยพบ ขอบคุณคน
marcovega

เป็นความพยายามที่ยอดเยี่ยมโดยพื้นฐานแล้วมันใช้งานได้เมื่อฉันทิ้งสิ่งนี้ลงไปซึ่งมากกว่าที่ฉันสามารถพูดได้สำหรับปลั๊กอินอื่น ๆ :) ประสิทธิภาพได้รับความนิยมอย่างมาก แต่ฉันคิดว่ามันค่อนข้างจะได้รับจากการใช้งานที่ไม่ติดเนทีฟ
jClark

นี่เป็นจุดเริ่มต้นที่ยอดเยี่ยม! ฉันรวม$.cssฟังก์ชันไว้ใน a requestAnimationFrameและเพิ่มฟังก์ชัน destroy / unbind สำหรับการใช้งานในเฟรมเวิร์กส่วนหน้าสมัยใหม่เช่น vue / react ประสิทธิภาพไม่เป็นปัญหาอย่างแน่นอนหลังจากนั้น!
Christophe Marois

@Cristophe Marois คุณสามารถให้ตัวอย่างเกี่ยวกับ jsfiddle ได้ไหม?
DuArme

ขอบคุณ แต่รหัสนี้ใช้ไม่ได้กับแถบด้านข้างขนาดเล็กที่สั้นกว่าของวิวพอร์ต (ความสูงของวิวพอร์ต)
Seyed Abbas Seyedi

12

นี่คือตัวอย่างวิธีการใช้งาน:

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%;
}

การสาธิต: http://jsfiddle.net/ryanmaxwell/25QaE/

สิ่งนี้ทำงานได้ตามที่คาดไว้ในทุกสถานการณ์และได้รับการสนับสนุนอย่างดีใน IE ด้วย


ดูคำตอบนี้และอธิบายstackoverflow.com/questions/28428327/…
theinlwin

@Anoop Naik - เกือบจะดีที่ฉันกำลังมองหา ... Sticky-kit ใช้ไม่ได้กับแถบด้านข้างที่ยาวกว่าวิวพอร์ตของคุณ อย่างไรก็ตามฉันต้องการสิ่งที่ตรงกันข้าม: เมื่อฉันเลื่อนลงมันจะเกาะอยู่ด้านบนและในการเลื่อนขึ้นมันจะเกาะอยู่ที่ด้านล่าง ... คุณช่วยฉันด้วยการเปลี่ยนซอเล็กน้อยได้ไหม
Igor Laszlo

1
@IgorLaszlo เอาแน่เอาไว้เดี๋ยวจะอัพเดทให้ทราบ ...
Anoop Naik

สิ่งนี้ยังอธิบายถึงปัญหาของฉัน: "เมื่อองค์ประกอบที่มีตำแหน่ง: เหนียว" ติดอยู่ "และยาวกว่าวิวพอร์ตคุณจะเห็นเนื้อหาได้หลังจากเลื่อนไปที่ด้านล่างของคอนเทนเนอร์เท่านั้นมันจะดีมากถ้าองค์ประกอบ" ค้าง "เลื่อน ด้วยเอกสารและหยุดเมื่อเอกสารถึงขอบด้านล่างหากผู้ใช้เลื่อนกลับสิ่งเดียวกันจะเกิดขึ้นอีกครั้ง แต่กลับกัน " - เขียนโดยบุคคลอื่นที่มีปัญหาเดียวกัน ( stackoverflow.com/questions/47618271/… )
Igor Laszlo

@ อรรณพนายก! ขอขอบคุณสำหรับความพยายามของคุณ แต่ขอเถอะฉันพบปลั๊กอิน Sticky jquery เพื่อแก้ไขปัญหาของฉัน: abouolia.github.io/sticky-sidebarขอบคุณอีกครั้ง!
Igor Laszlo

0

ฉันกำลังมองหาสิ่งเดียวกัน เห็นได้ชัดว่าฉันต้องการค้นหาคำที่คลุมเครือเพียงเพื่อค้นหาคำถามที่คล้ายกันกับกราฟิก ปรากฎว่าเป็นสิ่งที่ฉันกำลังมองหา ฉันไม่พบปลั๊กอินใด ๆ ดังนั้นฉันจึงตัดสินใจสร้างด้วยตัวเอง หวังว่าจะมีคนเห็นสิ่งนี้และปรับแต่งมัน

นี่คือตัวอย่าง html ที่รวดเร็วและสกปรกที่ฉันใช้อยู่

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

นี่คือ 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();

    });
}

หมายเหตุบางส่วน:

  • .rectbtfad เป็นองค์ประกอบด้านล่างสุดในแถบด้านข้างของฉัน
  • ฉันใช้ความสูงของ #masthead ของฉันเนื่องจากเป็นส่วนหัวที่เหนียวจึงจำเป็นต้องชดเชย
  • มีการตรวจสอบ col-2 float เนื่องจากฉันใช้การออกแบบที่ตอบสนองและไม่ต้องการให้เปิดใช้งานบนหน้าจอขนาดเล็ก

หากใครสามารถปรับแต่งเพิ่มเติมได้อีกสักหน่อยจะดีมาก


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

ตัวอย่างการทำงาน: https://jsfiddle.net/L7xoopst/6/


เพิ่มคำอธิบายเล็กน้อย?
HaveNoDisplayName

หากคุณอัปเดตความสูงภายในรายการติดหนึบสิ่งนี้มีปัญหา
Callam

0

มีปลั๊กอินที่ค่อนข้างไม่รู้จักในที่เก็บ Wordpress ซึ่งเรียกว่า WP Sticky Sidebar ปลั๊กอินทำสิ่งที่คุณต้องการ (Sticky sidebar: ติดด้านล่างเมื่อเลื่อนลงด้านบนเมื่อเลื่อนขึ้น) WP Sticky Sidebar Wordpress Repository Link: https://wordpress.org/plugins/mystickysidebar/


ขอบคุณสำหรับข้อมูล! ทำงานได้อย่างสมบูรณ์แบบ มันตลกว่าพฤติกรรมภาพประกอบจะเหมือนกันสำหรับปลั๊กอินภาพที่โดดเด่น :)
Oksana Romaniv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.