Thanh bên dính: dính vào dưới cùng khi cuộn xuống, trên cùng khi cuộn lên


94

Tôi đã tìm kiếm một giải pháp cho vấn đề thanh bên dính của tôi một thời gian. Tôi có một ý tưởng cụ thể về cách tôi muốn nó hoạt động; một cách hiệu quả, tôi muốn nó dính xuống dưới cùng khi bạn cuộn xuống, và ngay khi bạn cuộn lên, tôi muốn nó dính vào trên cùng, trong một chuyển động linh hoạt (không nhảy). Tôi không thể tìm thấy một ví dụ về những gì tôi đang cố gắng đạt được, vì vậy tôi đã tạo ra một hình ảnh mà tôi hy vọng sẽ minh họa cho điểm rõ ràng hơn:

Thanh bên dính: dính vào dưới cùng khi cuộn xuống, trên cùng khi cuộn lên

  1. Thanh bên nằm dưới tiêu đề.
  2. Khi bạn cuộn xuống, thanh bên vẫn ngang bằng với nội dung của trang để bạn có thể cuộn qua cả thanh bên và nội dung.
  3. Tiếp cận dưới cùng của thanh bên, thanh bên dính vào cuối khung nhìn (hầu hết các plugin chỉ cho phép dính lên trên, một số cho phép dính xuống dưới không cho phép cả hai).
  4. Tiếp cận dưới cùng, thanh bên nằm phía trên chân trang.
  5. Khi bạn cuộn lên, thanh bên vẫn ngang bằng với nội dung để bạn có thể cuộn lại qua nội dung và thanh bên.
  6. Tiếp cận đầu thanh bên, thanh bên dính vào đầu khung nhìn.
  7. Tiếp cận trên cùng và thanh bên nằm trở lại bên dưới tiêu đề.

Tôi hy vọng đây là đủ thông tin. Tôi đã tạo jsfiddle để kiểm tra bất kỳ plugin / tập lệnh nào mà tôi đã đặt lại cho câu hỏi này: http://jsfiddle.net/jslucas/yr9gV/2/ .

Câu trả lời:


25

+1 cho hình ảnh rất đẹp và bắt mắt.

Tôi biết đó là một câu hỏi cũ, nhưng tôi tình cờ tìm thấy câu hỏi tương tự do bạn đăng trên forum.jquery.com và một câu trả lời ở đó (bởi @ tucker973) , đề xuất một thư viện tuyệt vời để làm điều này và muốn chia sẻ nó ở đây.

Nó có tên là stick -kit của @leafo

Ở đây bạn có mã của một ví dụ rất cơ bản mà tôi đã chuẩn bị và một bản demo đang hoạt động để xem kết quả.

Tất nhiên, tất cả các khoản tín dụng đều thuộc về người tạo plugin, tôi chỉ làm ví dụ này để hiển thị ở đây. Tôi cần đạt được kết quả tương tự như bạn đã làm và thấy plugin này rất hữu ích.


Tôi sử dụng plugin nhỏ này như bạn đề xuất, nhưng chiều rộng thay đổi sau khi nó ở trên cùng. Làm thế nào tôi có thể làm cho nó không thay đổi?
vijayrana

Chào bạn @gmo! Tôi đang tìm kiếm điều tương tự nhưng nó không làm việc (không dính trên đầu trên cuộn lên) khi cuộn dài hơn viewport ...
Igor Laszlo

13

Cảm ơn vì đồ họa tuyệt vời. Tôi cũng đang tìm giải pháp cho thách thức này!

Thật không may, câu trả lời khác được đăng ở đây không giải quyết yêu cầu số 5 quy định khả năng cuộn lại qua thanh bên một cách trơn tru.

Tôi đã tạo một fiddle thực hiện tất cả các yêu cầu: http://jsfiddle.net/bN4qu/5/

Logic cốt lõi cần được thực hiện là:

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

Trong fiddle, tôi sử dụng biến đổi CSS3 để di chuyển phần tử mục tiêu xung quanh, vì vậy nó sẽ không hoạt động trong ví dụ: IE <9. Tuy nhiên, logic là hợp lý khi sử dụng một cách tiếp cận khác.

Ngoài ra, tôi đã sửa đổi fiddle của bạn để thanh bên dính có nền gradient. Điều này giúp cho thấy rằng hành vi phù hợp đang được trưng bày.

Tôi hy vọng điều này hữu ích cho ai đó!


2
Đối với bất kỳ ai đang tìm kiếm câu trả lời, câu trả lời này của Travis là câu trả lời hoàn hảo nhất mà tôi tìm thấy cho đến nay. Cảm ơn anh bạn.
marcovega

Một nỗ lực tuyệt vời, về cơ bản nó chỉ hoạt động khi tôi bỏ qua điều này, nhiều hơn những gì tôi có thể nói đối với các plugin khác :) Hiệu suất đạt được một thành công lớn, nhưng tôi nghĩ đó là khá nhiều với bất kỳ triển khai dính không phải gốc nào.
jClark

Đây là một điểm khởi đầu tuyệt vời! Tôi đã gói $.csshàm trong một requestAnimationFramevà thêm một hàm hủy / hủy liên kết để sử dụng trong các khuôn khổ giao diện người dùng hiện đại như vue / react. Hiệu suất hoàn toàn không phải là một vấn đề sau đó!
Christophe Marois

@Cristophe Marois, bạn có thể cung cấp một ví dụ về jsfiddle được không?
DuArme 07/07/19

cảm ơn, nhưng mã này không làm việc cho sidebar nhỏ mà ngắn của khung nhìn (chiều cao của khung nhìn)
Seyed Abbas Seyedi

12

Dưới đây là một ví dụ về cách triển khai điều này:

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/

Điều này hoạt động như mong đợi trong tất cả các tình huống và cũng được hỗ trợ tốt trong IE.


xem câu trả lời này và giải thích stackoverflow.com/questions/28428327/…
theinlwin

@Anoop Naik - đó gần như là thứ tốt mà tôi đang tìm kiếm ... bộ dính không hoạt động cho các thanh bên dài hơn khung nhìn, hoạt động của bạn. Tuy nhiên tôi muốn ngược lại: khi tôi cuộn xuống, nó dính trên cùng, và khi cuộn lên, nó dính ở dưới ... bạn có thể giúp tôi với sự thay đổi nhỏ đó trong một lần nghịch ngợm không?
Igor Laszlo

1
@IgorLaszlo chắc chắn, gimme một lúc nào đó, sẽ cập nhật cho bạn trong thời gian ngắn ...
Anoop Naik

Điều này cũng giải thích sự cố của tôi: "Khi phần tử có vị trí: dính bị" kẹt "và dài hơn chế độ xem, bạn chỉ có thể xem nội dung của phần tử đó sau khi cuộn xuống cuối vùng chứa. Sẽ rất tuyệt nếu phần tử" bị kẹt "được cuộn với tài liệu và dừng lại, khi nó chạm đến mép dưới. Nếu người dùng cuộn lại, điều tương tự sẽ xảy ra một lần nữa, nhưng ngược lại. " - được viết bởi một người khác có cùng vấn đề ( stackoverflow.com/questions/47618271/… )
Igor Laszlo

@Anoop Naik! Cảm ơn nỗ lực của bạn nhưng hãy để nó làm ơn, tôi đã tìm thấy plugin Sticky jquery để giải quyết vấn đề của mình: abouolia.github.io/sticky-sidebar Cảm ơn bạn một lần nữa!
Igor Laszlo

0

Tôi đã tìm kiếm điều tương tự. Rõ ràng tôi cần tìm kiếm một số thuật ngữ khó hiểu chỉ để tìm một câu hỏi tương tự với hình ảnh. Hóa ra đó chính xác là những gì tôi đang tìm kiếm. Tôi không thể tìm thấy bất kỳ plugin nào nên tôi quyết định tự tạo. Hy vọng rằng ai đó sẽ nhìn thấy điều này và tinh chỉnh nó.

Đây là một html mẫu nhanh và bẩn mà tôi đang sử dụng.

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

Đây là jQuery tôi đã tạo:

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

    });
}

Một số lưu ý:

  • .rectbtfad là phần tử dưới cùng nhất trong thanh bên của tôi
  • Tôi đang sử dụng chiều cao của #masthead vì đó là tiêu đề cố định nên cần bù đắp cho nó
  • Có một kiểm tra cho phao col-2 vì tôi đang sử dụng thiết kế đáp ứng và không muốn điều này kích hoạt trên màn hình nhỏ hơn

Nếu ai đó có thể tinh chỉnh điều này hơn một chút thì sẽ rất tuyệt.


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

Ví dụ làm việc: https://jsfiddle.net/L7xoopst/6/


thêm một chút giải thích?
HaveNoDisplayName

Nếu bạn cập nhật chiều cao trong mục dính, điều này có một số vấn đề
Callam

0

Có một plugin tương đối không được biết đến trong kho Wordpress được gọi là WP Sticky Sidebar. Plugin thực hiện chính xác những gì bạn muốn (Sticky sidebar: dính vào dưới cùng khi cuộn xuống, trên cùng khi cuộn lên) Liên kết kho lưu trữ WP Sticky Sidebar Wordpress: https://wordpress.org/plugins/mystickysidebar/


Cảm ơn bạn về thông tin! Hoạt động hoàn hảo. Thật buồn cười rằng hành vi minh họa đồ họa là như nhau cho cắm hình ảnh đặc sắc :)
Oksana Romaniv
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.