粘边栏:向下滚动时固定在底部,向上滚动时固定在顶部


94

我一直在寻找一段时间,以解决粘性侧栏问题。我对自己的行为有一个特定的想法;实际上,当您向下滚动时,我希望它粘在底部,然后当您向上滚动时,我希望它以流畅的运动(不跳动)粘在顶部。我找不到我要实现的目标的示例,因此我创建了一个图像,希望可以更清楚地说明这一点:

粘边栏:向下滚动时固定在底部,向上滚动时固定在顶部

  1. 边栏位于标题下方。
  2. 向下滚动时,侧栏保持与页面内容的水平,以便您可以滚动浏览侧栏和内容。
  3. 到达侧边栏的底部,侧边栏将粘在视口的底部(大多数插件仅允许粘在顶部,有些插件允许粘在底部而不是两者都允许)。
  4. 到达底部,侧边栏位于页脚上方。
  5. 向上滚动时,侧边栏与内容保持水平,因此您可以再次滚动浏览内容和侧边栏。
  6. 到达侧边栏的顶部,侧边栏粘贴到视口的顶部。
  7. 到达顶部,边栏位于标题下方。

我希望这是足够的信息。我创建了一个jsfiddle来测试所有插件/脚本,对此问题我已对其进行了重置:http : //jsfiddle.net/jslucas/yr9gV/2/ .

Answers:


25

+1到非常精美的图片。

我知道这是一个老问题,但是我随便在forum.jquery.com上找到了您发布的相同问题,并在找到了一个答案(by @ tucker973),建议使用一个不错的库来做这个,并想在这里分享。

这就是所谓的粘性套件@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函数包装在中,requestAnimationFrame并添加了destroy / unbind函数,以在vue / react之类的现代前端框架中使用。之后,性能绝对不是问题!
Christophe Marois

@Cristophe Marois能否在jsfiddle上提供示例?
DuArme

谢谢,但是这个代码的小边栏不工作,视口较短(视口的高度)
赛义德·阿巴斯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中也得到了很好的支持。



@Anoop Naik-这几乎是我要寻找的东西。。。sticky-kit对于边栏比视口长的侧边栏不起作用,您的工作正常。但是我想相反:当我向下滚动时,它粘在顶部,而向上滚动时,它粘在底部...您能帮我做些小提琴吗?
伊戈尔·拉斯洛

1
@IgorLaszlo当然,gimme会在一段时间内为您更新...
Anoop Naik

这也解释了我的问题:“当具有位置:sticky的元素被“粘住”并且比视口更长时,您只能在滚动到容器底部后才能看到其内容。如果滚动了“ stuck”元素,那将会很酷一旦到达底部,文档就会停下来。如果用户向后滚动,同样的事情将会再次发生,但是相反。-写的其他人谁拥有了同样的问题(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是我的侧栏中最底层的元素
  • 我使用#标头的高度,因为它是粘性标头,因此需要对其进行补偿
  • 因为我使用的是响应式设计,所以不检查col-2浮动,并且不想在较小的屏幕上激活它

如果有人可以进一步完善它,那就太好了。


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 2015年

如果您更新粘性项目内的高度,
则会遇到

0

在Wordpress存储库中有一个相对未知的插件,称为WP Sticky Sidebar。该插件完全可以实现您想要的功能(Sticky侧边栏:向下滚动时停留在底部,向上滚动时向上停留)WP Sticky Sidebar Wordpress存储库链接:https : //wordpress.org/plugins/mystickysidebar/


谢谢(你的)信息!工作完美。有趣的是,行为插图图形与插件精选图片相同:)
Oksana Romaniv '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.