Подтвердить что ты не робот

Липкая боковая панель: придерживайтесь нижней части при прокрутке вниз, сверху при прокрутке вверх

Я искал какое-то время для решения моей липкой проблемы с боковой панелью. У меня есть конкретное представление о том, как я хотел бы, чтобы он действовал; эффективно, я хотел бы, чтобы он придерживался дна, когда вы прокручиваете вниз, а затем, как только вы прокрутите резервную копию, я бы хотел, чтобы он придерживался вершины, в движении жидкости (без прыжков). Я не могу найти пример того, чего я пытаюсь достичь, поэтому я создал изображение, которое, я надеюсь, иллюстрирует ясность точки:

Sticky sidebar: stick to bottom when scrolling down, top when scrolling up

  • Боковая панель находится под заголовком.
  • Когда вы прокручиваете вниз, боковая панель остается на уровне содержимого страницы, чтобы вы могли прокручивать как боковую панель, так и содержимое.
  • Подойдите к нижней части боковой панели, боковая панель приклеивается к нижней части окна просмотра (большинство плагинов допускают только прилипание к вершине, некоторые, которые позволяют придерживаться снизу, не позволяют обоим).
  • Достигните дна, боковая панель сидит над нижним колонтитулом.
  • Когда вы прокручиваете резервную копию, боковая панель остается на уровне контента, чтобы снова просматривать содержимое и боковую панель.
  • Поверните верхнюю часть боковой панели, боковая панель встанет в верхнюю часть окна просмотра.
  • Верните верх, а боковая панель сидит обратно под заголовком.

Надеюсь, этого достаточно. Я создал jsfiddle для тестирования любых плагинов/скриптов, которые у меня есть reset для этого вопроса: http://jsfiddle.net/jslucas/yr9gV/2/ .

4b9b3361

Ответ 1

+1 к очень приятному и иллюстративному изображению.

Я знаю, это старый вопрос, но я случайно нашел тот же вопрос, который вы разместили в forum.jquery.com и один ответ там (by @tucker973) предложил одну красивую библиотеку, чтобы сделать это, и хотел бы поделиться им здесь.

Он назвал липким набором @leafo

Здесь у вас есть код очень простого примера, который я подготовил, и рабочая демонстрация, чтобы увидеть результат.

/*!
 * Sticky-kit
 * A jQuery plugin for making smart sticky elements
 *
 * Source: http://leafo.net/sticky-kit/
 */

$(function() {
  $(".sidebar").stick_in_parent({
    offset_top: 10
  });
});
* {
  font-size: 10px;
  color: #333;
  box-sizing: border-box;
}
.wrapper,
.header,
.main,
.footer {
  padding: 10px;
  position: relative;
}
.wrapper {
  border: 1px solid #333;
  background-color: #f5f5f5;
  padding: 10px;
}
.header {
  background-color: #6289AE;
  margin-bottom: 10px;
  height: 100px;
}
.sidebar {
  position: absolute;
  padding: 10px;
  background-color: #ccc;
  height: 300px;
  width: 100px;
  float: left;
}
.main {
  background-color: #ccc;
  height: 600px;
  margin-left: 110px;
}
.footer {
  background-color: #6289AE;
  margin-top: 10px;
  height: 250px;
}
.top {
  position: absolute;
  top: 10px;
}
.bottom {
  position: absolute;
  bottom: 10px;
}
.clear {
  clear: both;
  float: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://leafo.net/sticky-kit/src/jquery.sticky-kit.js"></script>
<div class="wrapper">
  <div class="header"> <a class="top">header top</a>
    <a class="bottom">header bottom</a>

  </div>
  <div class="content">
    <div class="sidebar"> <a class="top">sidebar top</a>
      <a class="bottom">sidebar bottom</a>

    </div>
    <div class="main"> <a class="top">main top</a>
      <a class="bottom">main bottom</a>

    </div>
    <div class="clear"></div>
  </div>
  <div class="footer"> <a class="top">footer top</a>
    <a class="bottom">footer bottom</a>

  </div>
</div>

Ответ 2

Спасибо за отличную графику. Я также искал решение этой проблемы!

К сожалению, в другом ответе, размещенном здесь, не рассматривается требование №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. Логика звучит, однако, для использования другого подхода.

Кроме того, я изменил вашу скрипку так, чтобы липкая боковая панель имела градиентный фон. Это помогает показать, что проявляется надлежащее поведение.

Я надеюсь, что это кому-то полезно!

Ответ 3

Вот пример того, как реализовать это:

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.

Ответ 4

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/

Ответ 5

Я искал то же самое. По-видимому, мне нужно было искать некоторые неясные условия, чтобы найти аналогичный вопрос с графикой. Оказывается, именно то, что я искал. Я не мог найти никаких плагинов, поэтому решил сделать это сам. Надеюсь, кто-то увидит это и усовершенствует его.

Вот быстрый и грязный образец 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, потому что это липкий заголовок, поэтому он должен компенсировать его
  • Там есть проверка на float col-2, так как я использую отзывчивый дизайн и не хочу, чтобы эта активация на меньших экранах

Если кто-то может уточнить это немного больше, это будет здорово.