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


94

Я вже деякий час шукаю рішення моєї проблеми з липкою бічною панеллю. Я конкретно уявляю, як би я хотів, щоб це діяло; фактично, я хотів би, щоб він прилипав до низу, коли ви прокручуєте вниз, а потім, як тільки ви прокручуєте назад, я хотів би, щоб він прилипав до верху, плавним рухом (без стрибків). Я не можу знайти приклад того, чого намагаюся досягти, тому створив образ, який, сподіваюся, проілюструє суть чіткіше:

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

  1. Бічна панель розташована під заголовком.
  2. Під час прокрутки бічної панелі вниз рівень вмісту сторінки залишається рівним, щоб ви могли прокручувати як бічну панель, так і вміст.
  3. Дойдіть до нижньої частини бічної панелі, бокова панель прилипає до нижньої частини області перегляду (більшість плагінів дозволяють притримуватися лише доверху, деякі, що дозволяють дотримуватися нижньої частини, не дозволяють обидва).
  4. Дойдіть до нижньої частини, бічна панель розташована над колонтитулом.
  5. Під час прокрутки назад бічна панель залишається на рівні з вмістом, тому ви можете прокрутити вміст і бічну панель знову.
  6. Дойдіть до верхньої частини бічної панелі, бічна панель прилипає до верхньої частини області перегляду.
  7. Дістаньтеся до верхньої частини, і бічна панель розташується назад під заголовком.

Сподіваюся, цього достатньо інформації. Я створив jsfiddle для тестування будь-яких плагінів / сценаріїв, які я скинув для цього питання: http://jsfiddle.net/jslucas/yr9gV/2/ .

Відповіді:


25

+1 до дуже приємного та ілюстративного зображення.

Я знаю, що це старе запитання, але випадково я знайшов те саме запитання, опубліковане вами на forum.jquery.com, і одну відповідь там (@ tucker973) , запропонував зробити одну приємну бібліотеку і хотів поділитися ним тут.

Це називається липким набором по @leafo

Тут у вас є код дуже базового прикладу, який я підготував, і робоча демонстрація, щоб побачити результат.

Звичайно, всі кредити дістаються творцю плагіна, я лише зробив цей приклад, щоб показати його тут. Мені потрібно досягти того самого результату, що й після вас, і цей плагін виявився дуже корисним.


Я використовую цей невеликий плагін, як ви пропонуєте, але ширина змінюється після того, як він приклеїться зверху. Як я можу зробити його незмінним?
vijayrana

Привіт @gmo! Я шукаю те саме, але воно не працює (не тримається зверху при прокрутці вгору), коли смужка прокрутки довша за область перегляду ...
Ігор Ласло

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
Для тих, хто шукає відповіді, цей Тревіс є найбільш бездоганним, який я знайшов на сьогодні. Спасибі людино.
marcovega

Чудова спроба, це в основному просто спрацювало, коли я впустив це, що є більшим, ніж я міг би сказати для інших плагінів :) Продуктивність отримала великий удар, але я думаю, що це в значній мірі дане з будь-якою нерідною липкою реалізацією.
jClark

Це було чудовою відправною точкою! Я обернув $.cssфункцію в requestAnimationFrameі додав функцію знищення / розв'язування для використання в сучасних фронтенд-фреймворках, таких як vue / response. Після цього продуктивність абсолютно не проблема!
Крістоф Маруа

@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 не працює для бічних панелей, які довші за область перегляду, ваша працює. Однак мені хотілося б протилежного: коли я прокручую вниз, він тримається вгорі, а при прокручуванні вгору - внизу ... чи можете ви допомогти мені, будь ласка, з цією невеликою переробкою в скрипці, будь ласка?
Ігор Ласло

1
@IgorLaszlo впевнений, дай мені трохи часу, оновить тебе через деякий час ...
Anoop Naik

Це також пояснює мою проблему: "Коли елемент із позицією: sticky" застряг "і довший за область перегляду, ви можете побачити його вміст лише після прокрутки внизу контейнера. Було б круто, якби" застряглий "елемент прокрутив з документом і зупинено, як тільки він досягне нижнього краю. Якщо користувач прокрутить назад, те саме повториться знову, але навпаки. " - написано іншою особою, яка має таку ж проблему ( stackoverflow.com/questions/47618271/… )
Ігор Ласло

@Anoop Naik! Дякуємо за ваші зусилля, але дозвольте, будь ласка, я знайшов Sticky jquery плагін для вирішення моєї проблеми: abouolia.github.io/sticky-sidebar Ще раз дякую!
Ігор Ласло

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, тому що це липкий заголовок, тому його потрібно компенсувати
  • Існує перевірка на flo-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

Якщо ви оновите висоту в межах липкого предмета, це має деякі проблеми
Калам

0

У сховищі Wordpress є відносно невідомий плагін, відомий як WP Sticky Sidebar. Плагін робить саме те, що ви хотіли (липка бічна панель: дотримуйтесь знизу при прокрутці вниз, зверху при прокрутці вгору) WP Sticky Sidebar репозиторій Wordpress Посилання: https://wordpress.org/plugins/mystickysidebar/


Дякую за інформацію! Працював ідеально. Забавно, що графічні ілюстрації поведінки однакові для зображень із плагінами :)
Оксана Романів
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.