停止固定位置在页脚

55

我正在寻找一个解决方案,用于解决将一个固定对象停留在页面底部的常见问题。

我有一个固定的“分享”框,位于屏幕左下角,我不希望它滚动到页脚上方,因此我需要它停留在页脚大约10px 的位置。

我查看了其他类似的问题,并尝试了一些方法。目前我找到的最接近/最简单的样例是http://jsfiddle.net/bryanjamesross/VtPcm/ 但是我无法使其适用于我的情况。

这是分享框的HTML:

    <div id="social-float">
        <div class="sf-twitter">
            ...
        </div>

        <div class="sf-facebook">
            ...
        </div>

        <div class="sf-plusone">
            ...
        </div>
    </div>

...还有CSS:

#social-float{
position: fixed;
bottom: 10px;
left: 10px;
width: 55px;
padding: 10px 5px;
text-align: center;
background-color: #fff;
border: 5px solid #ccd0d5;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
display: none;
}
元素的选择器是#footer,它没有固定高度,如果这会有所影响,请帮我创建一个简单的jQuery解决方案,非常感谢!

Fiddle与您所需的有何不同? - Derk Arts
代码相关内容翻译:Fiddle 中的侧边栏与浏览器窗口没有固定位置。我不知道,这可能是完全相同的概念,但我尝试了一下,发现无法在我的情况下使其正常工作。我需要该框位于窗口左下角,直到它到达页脚,然后随页面滚动。 - scferg5
14个回答

72

演示实例

首先,在每次滚动页面时检查其偏移量。

$(document).scroll(function() {
    checkOffset();
});

如果一个元素在页脚之前下降到小于10像素,将其位置设置为绝对定位。

function checkOffset() {
    if($('#social-float').offset().top + $('#social-float').height() 
                                           >= $('#footer').offset().top - 10)
        $('#social-float').css('position', 'absolute');
    if($(document).scrollTop() + window.innerHeight < $('#footer').offset().top)
        $('#social-float').css('position', 'fixed'); // restore when you scroll up
}

请注意,#social-float的父元素应该是页脚元素的兄弟元素。

<div class="social-float-parent">
    <div id="social-float">
        something...
    </div>
</div>
<div id="footer">
</div>

祝你好运 :)


谢谢回复。现在,当滚动条滚动到页脚时,框只会闪烁。我需要在CSS中更改什么吗? - scferg5
哦,抱歉,这是因为位置样式一直在切换,因为它被固定了。尝试使用'>='运算符替换'>'。 - Sang
仍然闪烁 :( 这是正在发生的情况的屏幕录像,如果有帮助的话:http://youtu.be/aNnTARjYPOc - scferg5
1
看起来你的浮动div的父元素包含了页脚...我为你创建了一个jsfiddle并检查了我的答案。它粘得很好,但是当我向上滚动时它没有恢复原样。所以我添加了一些代码来解决这个问题。这是fiddle链接:http://jsfiddle.net/Kkv7X/,我会再次编辑我的答案 :) - Sang
有人知道如何实现Bootstrap吗? - maciek
显示剩余2条评论

27

我刚刚在我正在工作的网站上解决了这个问题,并且希望分享一下,以便能够帮助到其他人。

我的解决方案是通过计算页脚到页面顶部的距离,如果用户向下滚动超过此距离,则使用负边距将侧边栏拉回到顶部。

$(window).scroll(() => { 
  // Distance from top of document to top of footer.
  topOfFooter = $('#footer').position().top;
  // Distance user has scrolled from top, adjusted to take in height of sidebar (570 pixels inc. padding).
  scrollDistanceFromTopOfDoc = $(document).scrollTop() + 570;
  // Difference between the two.
  scrollDistanceFromTopOfFooter = scrollDistanceFromTopOfDoc - topOfFooter;

  // If user has scrolled further than footer,
  // pull sidebar up using a negative margin.
  if (scrollDistanceFromTopOfDoc > topOfFooter) {
    $('#cart').css('margin-top',  0 - scrollDistanceFromTopOfFooter);
  } else  {
    $('#cart').css('margin-top', 0);
  }
});

1
这个方法非常有效。最佳答案不可行,因为我的侧边栏父元素不是页脚div的兄弟元素。这个答案对div的堆叠顺序要求不那么严格。 - Dan382
非常棒的答案。它帮助了我的滚动监听,当我向下滚动时会重叠页脚。非常感谢您。 - Bunny Joel
太棒了!非常容易操作(之前的JS解决方案对于不太懂的人来说有点吓人)。非常感谢! - Claire
完美运行。 - Polar
很棒的解决方案!我也将这段代码提取到自己的函数中,并在scroll()和$(window).resize()上调用它,以考虑当他们调整浏览器窗口大小时的情况(这并不总是调用scroll()但可能会改变足够的大小以导致重叠) - Tomer Shemesh
不错的解决方案,但是我的页脚高度会根据响应式变化.. 我该如何处理这个问题呢? - undefined

20

这是 @Sang 的解决方案,但没有使用 JQuery。

var socialFloat = document.querySelector('#social-float');
var footer = document.querySelector('#footer');

function checkOffset() {
  function getRectTop(el){
    var rect = el.getBoundingClientRect();
    return rect.top;
  }
  
  if((getRectTop(socialFloat) + document.body.scrollTop) + socialFloat.offsetHeight >= (getRectTop(footer) + document.body.scrollTop) - 10)
    socialFloat.style.position = 'absolute';
  if(document.body.scrollTop + window.innerHeight < (getRectTop(footer) + document.body.scrollTop))
    socialFloat.style.position = 'fixed'; // restore when you scroll up
  
  socialFloat.innerHTML = document.body.scrollTop + window.innerHeight;
}

document.addEventListener("scroll", function(){
  checkOffset();
});
div.social-float-parent { width: 100%; height: 1000px; background: #f8f8f8; position: relative; }
div#social-float { width: 200px; position: fixed; bottom: 10px; background: #777; }
div#footer { width: 100%; height: 200px; background: #eee; }
<div class="social-float-parent">
    <div id="social-float">
        float...
    </div>
</div>
<div id="footer">
</div>


7

现在可以使用 position: sticky 来实现。

body,
html {
  height: 100%;
}

body {
  background-color: linen;
  margin: 0;
}


body,
main {
  display: flex;
  flex-direction: column;
}

main,
section {
  flex: 1;
}

main {
  min-height: 200vh;
}

.sticky {
  position: sticky;
  top: 0;
  background-color: lightcoral;
  padding: 1rem;
}

p {
  padding: 0 1rem;
}

footer {
  background-color: lightblue;
  padding: 15rem 1rem;
}
<main>
  <section>
    <div class="sticky">
      <h2>I am sticky<h2>
    </div>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. </p>

  <p>Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa. Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. </p>

  <p>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices. Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. </p>

  <p>Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus. Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. Nulla facilisi. Integer lacinia sollicitudin massa. </p>

  <p>Cras metus. Sed aliquet risus a tortor. Integer id quam. Morbi mi. Quisque nisl felis, venenatis tristique, dignissim in, ultrices sit amet, augue. Proin sodales libero eget ante. Nulla quam. Aenean laoreet. Vestibulum nisi lectus, commodo ac, facilisis ac, ultricies eu, pede. Ut orci risus, accumsan porttitor, cursus quis, aliquet eget, justo. Sed pretium blandit orci. Ut eu diam at pede suscipit sodales. Aenean lectus elit, fermentum non, convallis id, sagittis at, neque. Nullam mauris orci, aliquet et, iaculis et, viverra vitae, ligula. </p>
  </section>
  <footer>
    <h2>I am a footer<h2>
  </footer>
</main>


4
我最近也遇到了同样的问题,在这里分享我的解决方案: Preventing element from displaying on top of footer when using position:fixed 你可以通过使用元素的 position 属性和 jQuery 来实现解决方案,切换默认值 (对于 divsstatic),fixedabsolute。 您还需要为固定元素提供一个容器元素。最后,为了防止固定元素在页脚上方,该容器元素不能是页脚的父元素。
JavaScript 部分涉及计算固定元素与文档顶部之间的像素距离,并将其与滚动条相对于窗口对象的当前垂直位置 (即页面可见区域上方隐藏的像素数) 进行比较,每当用户滚动页面时。 当向下滚动时,固定元素即将从上面消失,我们会将其位置更改为固定,并固定在页面顶部。
这会导致在滚动到底部时,固定元素会覆盖页脚,特别是如果浏览器窗口很小。 因此,我们将计算页脚与文档顶部之间的像素距离,并将其与固定元素的高度加上滚动条的垂直位置进行比较:当固定元素即将超过页脚时,我们将其位置更改为绝对位置,并固定在页脚上方。
以下是一个通用示例。
HTML 结构:
<div id="content">
    <div id="leftcolumn">
        <div class="fixed-element">
            This is fixed 
        </div>
    </div>
    <div id="rightcolumn">Main content here</div>
    <div id="footer"> The footer </div>
</div>  

CSS样式表如下:
#leftcolumn {
    position: relative;
}
.fixed-element {
    width: 180px;
}
.fixed-element.fixed {
    position: fixed;
    top: 20px;
}
.fixed-element.bottom {
    position: absolute;
    bottom: 356px; /* Height of the footer element, plus some extra pixels if needed */
}

这是JS代码:

// Position of fixed element from top of the document
var fixedElementOffset = $('.fixed-element').offset().top;
// Position of footer element from top of the document.
// You can add extra distance from the bottom if needed,
// must match with the bottom property in CSS
var footerOffset = $('#footer').offset().top - 36;

var fixedElementHeight = $('.fixed-element').height(); 

// Check every time the user scrolls
$(window).scroll(function (event) {

    // Y position of the vertical scrollbar
    var y = $(this).scrollTop();

    if ( y >= fixedElementOffset && ( y + fixedElementHeight ) < footerOffset ) {
        $('.fixed-element').addClass('fixed');
        $('.fixed-element').removeClass('bottom');          
    }
    else if ( y >= fixedElementOffset && ( y + fixedElementHeight ) >= footerOffset ) {
        $('.fixed-element').removeClass('fixed');           
        $('.fixed-element').addClass('bottom');
    }
    else {
        $('.fixed-element').removeClass('fixed bottom');
    }

 });

3
$(window).scroll(() => {
    const footerToTop = $('.your-footer').position().top;
    const scrollTop = $(document).scrollTop() + $(window).height();
    const difference = scrollTop - footerToTop;
    const bottomValue = scrollTop > footerToTop ? difference : 0;
    $('.your-fixed-element').css('bottom', bottomValue);
});

代码总是好的,但是添加一些简短的注释/说明有助于解决原始问题。 - craigcaulfield
@Ali Klein 如果您将继承属性赋给底部值,而不是将其设置为0,这将非常有帮助。例如:const bottomValue = scrollTop > footerToTop ? difference : "inherit"; - Abhilash Poojary

3

我对第二个最受欢迎的答案进行了一些修改,因为我发现这种方法对我更有效。所做的更改使用window.innerHeight,因为它比添加导航栏自身高度的方法更加灵活(上述答案使用+570)。这允许代码在移动设备、平板电脑和桌面计算机上动态工作。

$(window).scroll(() => {
            //Distance from top fo document to top of footer
            topOfFooter = $('#footer').position().top;
             // Distance user has scrolled from top + windows inner height
             scrollDistanceFromTopOfDoc = $(document).scrollTop() + window.innerHeight;
             // Difference between the two.
             scrollDistanceFromTopOfFooter = scrollDistanceFromTopOfDoc - topOfFooter; 
            // If user has scrolled further than footer,
              if (scrollDistanceFromTopOfDoc > topOfFooter) {
                // add margin-bottom so button stays above footer.
                $('#floating-button').css('margin-bottom',  0 + scrollDistanceFromTopOfFooter);
              } else  {
                // remove margin-bottom so button goes back to the bottom of the page
                $('#floating-button').css('margin-bottom', 0);
              }
            });

不是修改边距,而是在我的if语句中使用了一些JavaScript来更改元素的位置(而不是“fixed”)。---> document.getElementById('elementId').style.position = "absolute"; - Mike Dubs
@young sir x,这个解决方案太完美了!我打开了大量的标签页尝试各种解决方案,而你的解决方案是最好的,可以让我的公告栏停在页脚上面。 - brandydoll

2
这对我很有帮助 -
HTML -
<div id="sideNote" class="col-sm-3" style="float:right;">

</div> 
<div class="footer-wrap">
        <div id="footer-div">
        </div>      
</div>

CSS -

#sideNote{right:0; margin-top:10px; position:fixed; bottom:0; margin-bottom:5px;}

#footer-div{margin:0 auto; text-align:center; min-height:300px; margin-top:100px; padding:100px 50px;}

JQuery -

function isVisible(elment) {
    var vpH = $(window).height(), // Viewport Height
        st = $(window).scrollTop(), // Scroll Top
        y = $(elment).offset().top;

    return y <= (vpH + st);
}

function setSideNotePos(){
    $(window).scroll(function() {
        if (isVisible($('.footer-wrap'))) {
            $('#sideNote').css('position','absolute');
            $('#sideNote').css('top',$('.footer-wrap').offset().top - $('#sideNote').outerHeight() - 100);
        } else {
            $('#sideNote').css('position','fixed');
            $('#sideNote').css('top','auto');
        }
    });
}

现在像这样调用此函数 -
$(document).ready(function() {
    setSideNotePos();
});

注意 - 这些Jquery函数是从stackoverflow上对另一个类似问题的答案中复制而来,但它并没有完全适用于我。因此,我修改了这些函数,如它们在这里所示。我认为侧边栏和页脚包装的位置等属性将取决于div结构以及其父级和兄弟元素。

当sideNote和footer-wraps是直接兄弟时,上述函数可以正常工作。


1
@Lionel Paulus的纯JS答案是最适合我的。我唯一遇到的问题是innerHTML计数器覆盖了我的元素。当我删除这个部分时,它完美地工作:
socialFloat.innerHTML = document.body.scrollTop + window.innerHeight;

var socialFloat = document.querySelector('#social-float');
var footer = document.querySelector('#footer');

function checkOffset() {
  function getRectTop(el){
    var rect = el.getBoundingClientRect();
    return rect.top;
  }
  
  if((getRectTop(socialFloat) + document.body.scrollTop) + socialFloat.offsetHeight >= (getRectTop(footer) + document.body.scrollTop) - 10)
    socialFloat.style.position = 'absolute';
  if(document.body.scrollTop + window.innerHeight < (getRectTop(footer) + document.body.scrollTop))
    socialFloat.style.position = 'fixed'; // restore when you scroll up
  
}

document.addEventListener("scroll", function(){
  checkOffset();
});


0
如果您的元素出现故障,这可能是因为当您将位置更改为relative时,页脚的Y位置会增加,试图将该项发送回fixed,从而创建一个循环。您可以通过在向上和向下滚动时设置两种不同的情况来避免这种情况。您甚至不需要引用固定元素,只需引用页脚和窗口大小即可。
const footer = document.querySelector('footer');
document.addEventListener("scroll", checkScroll);

let prevY = window.scrollY + window.innerHeight;
function checkScroll() {
  let footerTop = getRectTop(footer) + window.scrollY;
  let windowBottomY = window.scrollY + window.innerHeight;
  if (prevY < windowBottomY) {  // Scroll Down
    if (windowBottomY > footerTop)
      setScrolledToFooter(true) // using React state. Change class or change style in JS.
  } else { // Scroll Up
    if (windowBottomY <= footerTop)
      setScrolledToFooter(false)
  }
  prevY = windowBottomY
};

function getRectTop(el) {
  var rect = el.getBoundingClientRect();
  return rect.top;
}

并且元素在样式对象中的位置如下:

position: scrolledToFooter ? 'relative' : 'fixed'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接