javascript 侧边栏跟随滚动,但滚动自身,如果高于视口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4340143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sidebar that follows scroll, but scrolls self, if taller than viewport
提问by Jon Fabritius
(Hey, first post from a longtime lurker :)
(嘿,来自长期潜伏者的第一篇文章:)
I've built a simple sidebar that does the 'absolute-to-fixed' trick to stay on screen, but would like to take in account scenarios, where the sidebar is higher than the viewport.
我已经构建了一个简单的侧边栏,它执行“绝对到固定”技巧以留在屏幕上,但想考虑侧边栏高于视口的情况。
So I came up with this idea. It all starts as in above:
所以我想出了这个主意。这一切都从上面开始:
- On page load, the sidebar is drawn at starting location, some distance from viewport top.
- When the user scrolls the page, the sidebar moves with the content
- If sidebar fits the viewport vertically, it fixes to the top
- 在页面加载时,侧边栏绘制在起始位置,距视口顶部有一段距离。
- 当用户滚动页面时,侧边栏随着内容移动
- 如果侧边栏垂直适合视口,则它固定在顶部
But here it gets more dynamic:
但在这里它变得更加动态:
If sidebar is taller than the viewport, it continuesto scroll with the content until the bottomof the sidebar is reached, and it fixes there. The top of the sidebar scrolls beyond top of viewport.
When the user scrolls back towards page top, the sidebar moves with the content until the topof the sidebar is reached, and it fixes there. The bottom of the sidebar scrolls beyond the bottom of the viewport.
如果侧边栏比视口高,它会继续随着内容滚动,直到到达侧边栏的底部,然后固定在那里。侧边栏的顶部滚动到视口顶部之外。
当用户向页面顶部滚动时,侧边栏会随着内容移动,直到到达侧边栏的顶部,然后固定在那里。侧边栏的底部滚动到视口底部之外。
This way the sidebar reacts to scrolling as usual, while sticking around close enough to find on long pages.
通过这种方式,侧边栏像往常一样对滚动做出反应,同时保持足够近以在长页面上找到。
Any pointers to examples, or jQuery- friendly code snippets/guidelines would be much appreciated.
任何指向示例或 jQuery 友好代码片段/指南的指针将不胜感激。
回答by Ryan
I had this exact idea for a project, here's a example of how to implement it
我对一个项目有这个确切的想法,这是一个如何实施它的例子
回答by Temaruk
The behaviour you would like to achieve is called 'affix'. Twitter's Bootstrap front-end framework has a javascript component that can do what you would like to get. Please check the section about the affix component. In fact, there you can also see a demonstration of the desired behaviour, the menu in the left sidebar is affixed.
您想要实现的行为称为“词缀”。Twitter 的 Bootstrap 前端框架有一个 javascript 组件,可以做你想做的事。请检查关于词缀组件的部分。事实上,您还可以在那里看到所需行为的演示,左侧边栏中的菜单已粘贴。
You can define functions for the offset parameter of the affix init call, so it can be dynamically determined when to pin/unpin the element. To see an example in context, check the source of the above linked page, specifically look for application.js, it contains the setup of the affix that you can see on the left side. Here you can see the init code taken out of context:
您可以为词缀 init 调用的偏移参数定义函数,因此可以动态确定何时固定/取消固定元素。要在上下文中查看示例,请检查上述链接页面的来源,具体查找application.js,它包含您可以在左侧看到的词缀设置。在这里你可以看到脱离上下文的初始化代码:
// side bar
$('.bs-docs-sidenav').affix({
offset: {
top: function () { return $window.width() <= 980 ? 290 : 210 }
, bottom: 270
}
})
It is probably also worth to check in the page sources the docs.cssstylesheet, which contains some positioning and styling for the affixed element. Checking this might solve your problem, or at least could give you and idea.
可能还值得检查页面源docs.css样式表,其中包含附加元素的一些定位和样式。检查这可能会解决您的问题,或者至少可以给您和想法。
回答by Latrova
Since none of those examples suited me well, I did this and I like to share:
由于这些例子都不适合我,我做了这个,我想分享:
JS
JS
$(function () {
var element = $('.right-container');
var originalY = element.offset().top;
var lastOffset = $(document).scrollTop();
var diffToBottom = element.height() - $(window).height();
$(window).on('scroll', function (event) {
var scrollTop = $(window).scrollTop();
var currentOffset = $(document).scrollTop();
var isScrollingDown = currentOffset > lastOffset;
if (scrollTop > (diffToBottom + element.height())) {
if (!element.hasClass('relative')) {
element.css('top', scrollTop - (originalY + diffToBottom) + 'px');
element.addClass('relative');
}
if (isScrollingDown) {
var newTop = scrollTop < lastOffset ? 0 : scrollTop - (originalY + diffToBottom);
}
else if (scrollTop < element.offset().top) {
var newTop = scrollTop - (originalY);
}
element.stop(false, false).animate({
top: newTop
}, 300);
}
else {
if (scrollTop < originalY) {
element.removeClass('relative');
}
element.stop(false, false).animate({
top: scrollTop - (originalY)
}, 300);
}
lastOffset = currentOffset;
});
});
CSS
CSS
.relative {
position: relative;
}
It scrolls down smoothly when element hits bottom and scrolls up as well when top is hit.
当元素到达底部时它会平滑地向下滚动,当元素到达顶部时它也会向上滚动。
回答by Daniel R
You could use Sticky Sidebar https://abouolia.github.io/sticky-sidebar/#examples
您可以使用粘性边栏 https://aboulia.github.io/sticky-sidebar/#examples
You want the "Scrollable Sticky Element" behaviour See example here https://abouolia.github.io/sticky-sidebar/examples/scrollable-element.html
您想要“可滚动粘性元素”行为,请参见此处的示例https://aboulia.github.io/sticky-sidebar/examples/scrollable-element.html
回答by Krzysztof AN
This is very efficient and universal code in pure javascript:
这是纯 javascript 中非常高效和通用的代码:
//aside is your sidebar selector
var aside = document.querySelector('aside');
//sticky sidebar on scrolling
var startScroll = aside.offsetTop;
var endScroll = window.innerHeight - aside.offsetHeight;
var currPos = window.scrollY;
document.addEventListener('scroll', () => {
var asideTop = parseInt(aside.style.top.replace('px;', ''));
if (window.scrollY < currPos) {
//scroll up
if (asideTop < startScroll) {
aside.style.top = (asideTop + currPos - window.scrollY) + 'px';
} else if (asideTop > startScroll && asideTop != startScroll) {
aside.style.top = startScroll + 'px';
}
} else {
//scroll down
if (asideTop > endScroll) {
aside.style.top = (asideTop + currPos - window.scrollY) + 'px';
} else if (asideTop < (endScroll) && asideTop != endScroll) {
aside.style.top = endScroll + 'px';
}
}
currPos = window.scrollY;
});
//this code will bring to you sidebar on refresh page
function asideToMe() {
setTimeout(() => {
aside.style.top = startScroll + 'px';
}, 300);
}
asideToMe();
body{
padding: 0 20px;
}
#content {
height: 1200px;
}
header {
width: 100%;
height: 150px;
background: #aaa;
}
main {
float: left;
width: 65%;
height: 100%;
background: linear-gradient(180deg, rgba(255,255,255,1) 0%, rgba(0,0,0,1) 100%);
}
aside {
float: right;
width: 30%;
height: 800px;
position: sticky;
top: 100px;
background: linear-gradient(0deg, rgba(2,0,36,1) 0%, rgba(22,153,66,1) 51%, rgba(167,255,0,1) 100%);
}
footer {
width: 100%;
height: 70px;
background: #555;
}
<body>
<header>Header</header>
<div id="content">
<main>Content</main>
<aside>Sidebar</aside>
</div>
<footer>Footer</footer>
</body>
回答by chris.antonellis
You also asked for examples; One example I encounter on a regular basis is the Facebook right column of ads. It is taller than the viewport, and scrolls past the first or second ad and stops on the third. I believe this is defined by the location of the third ad as opposed to the overall height of the sidebar, but it is a working example.
您还要求提供示例;我经常遇到的一个例子是 Facebook 右栏的广告。它比视口高,滚动经过第一个或第二个广告并在第三个广告处停止。我相信这是由第三个广告的位置而不是侧边栏的整体高度定义的,但它是一个工作示例。
screenhots: http://i.imgur.com/dM3OZ.jpg/ top of page http://i.imgur.com/SxEZO.jpg/ further down
屏幕截图:http://i.imgur.com/dM3OZ.jpg / 页面顶部 http://i.imgur.com/SxEZO.jpg/ 再往下
回答by Robert
Something like this might work. I haven't tested it but in theory it looks good.
像这样的事情可能会奏效。我还没有测试过,但理论上它看起来不错。
$(function(){
var standardPosition = $('whatYouWantToScroll').offset().top;
// Cache the standard position of the scrolling element
$(window).scroll(function() {
if ($(this).scrollTop() < standardPosition) {
// if scroll pos is higher than the top of the element
$('whatYouWantToScroll').css({
position: 'relative',
top: '0px'
});
} else if ($(window).scrollTop() > $('somethingToReferenceOnTheBottom').offset().top-($('whatYouWantToScroll').height())) {
// if scroll position is lower than the top offset of the bottom reference
// + the element that is scrolling height
$('whatYouWantToScroll').css({
position: 'absolute',
top: $('somethingToReferenceOnTheBottom').offset().top-($('whatYouWantToScroll').height())
});
} else {
// otherwise we're somewhere inbetween, fixed scrolling.
$('whatYouWantToScroll').css({
position: 'fixed'
});
}
});
});
回答by Trey
I needed this exact functionality for a site, and this is what I came up with, it seems to work very nice... I know this post is old, but I assume some people may have an interest in this anyway;)
我需要一个网站的确切功能,这就是我想出来的,它似乎工作得很好......我知道这篇文章很旧,但我认为无论如何有些人可能对此感兴趣;)
(function($){
$(document).ready(function(){
sidebar_offset=$('#header').height()+10;
$(window).scroll(function(){
var sidebar=$('#primary');
if($(this).scrollTop()<sidebar_offset){
var height=$(window).height()-(sidebar_offset-$(this).scrollTop());
css={height:height,marginTop:0};
sidebar[0].scrollTop=0;
}else{
css.height=$(this).height();
if($(this).scrollTop()>sidebar_offset){
if(this.lastTop>$(this).scrollTop()){
sidebar[0].scrollTop=sidebar[0].scrollTop-(this.lastTop-$(this).scrollTop());
}else{
sidebar[0].scrollTop=sidebar[0].scrollTop+($(this).scrollTop()-this.lastTop);
}
css.marginTop=($(this).scrollTop()-sidebar_offset)+'px';
}else{
sidebar[0].scrollTop=0;
}
}
sidebar.css(css);
this.lastTop=$(this).scrollTop();
});
})(jQuery);

