垂直固定元素的位置,水平绝对定位

84

我想实现的目标是:

我需要一个按钮,它距离 div 右侧一定的距离,并且无论视口大小如何,始终与 div 边缘保持相同的距离,但会随着窗口滚动。

因此,该按钮始终距离 div 右侧 x 像素,同时始终距离视口顶部 y 像素。

这是否可行?

3个回答

58

基于另一个元素固定位置的元素

(免责声明: 此处提供的解决方案 技术上并不是 "水平绝对",正如问题标题所述,但确实实现了 OP 最初想要的,即固定位置元素距离另一个元素的右边缘为 'X' 距离,但垂直滚动时仍保持固定。)

我喜欢这些类型的 CSS 挑战。作为一个概念证明,是的,你可以得到你想要的。您可能需要根据自己的需求进行一些微调,但以下是一些样本 HTML 和 CSS,已通过 FireFox、IE8 和 IE7 的测试(当然,IE6 没有 position: fixed)。

HTML:

<body>
  <div class="inflow">
    <div class="positioner"><!-- may not be needed: see notes below-->
      <div class="fixed"></div>
    </div>
  </div>
</body>

CSS(边框和所有尺寸用于演示):
div.inflow {
  width: 200px; 
  height: 1000px; 
  border: 1px solid blue; 
  float: right; 
  position: relative; 
  margin-right: 100px;
}
div.positioner {position: absolute; right: 0;} /*may not be needed: see below*/
div.fixed {
  width: 80px; 
  border: 1px solid red; 
  height: 100px; 
  position: fixed; 
  top: 60px; 
  margin-left: 15px;
}

重点是不要在的水平方向上设置left或right,而是使用两个包装器div来设置水平位置。如果是固定宽度,则不需要,因为的左边距可以设置为容器的已知宽度。但是,如果您希望容器具有百分比宽度,则需要将推到的右侧。
编辑:有趣的是,当我在上设置overflow:hidden(如果需要),对于固定位置的div超出其他边界没有影响。显然,固定位置足以使其脱离包含div的上下文,以实现overflow。

6
非常荣幸 (字面上,很有趣去想出来)。 - ScottS
13
实际上它不能按预期工作。一旦出现水平滚动条并且您可以向右滚动,固定位置的框将不会与div保持相同的距离。在此页面向右滚动:http://jsfiddle.net/tXXtL/ - sparebytes
如果@sparebytes的意思是这样的话,那我同意。原始的OP只是在寻找一种方法来将固定元素水平定位到其他元素之外。在他的版本中,视口大小会改变(不会出现水平滚动条)。该元素仍然是一个“fixed”元素,并且不受滚动的影响。也许我应该更新问题标题以反映这一点。 - ScottS
@sparebytes--我选择在我的回答中添加免责声明,而不是更改帖子的标题,以便其他人不会被意外地捕捉到它所实现的内容。感谢您提醒我注意您的期望,以便可以加以解决。 - ScottS
3
@ScottS,很高兴看到你更新了答案。我认为仅使用CSS无法使一个维度“固定”,另一个维度“绝对”,必须通过JavaScript在滚动时更新坐标。 - sparebytes

15

在深入研究后(包括阅读这篇文章),我找不到一个我喜欢的解决方案。 接受的答案没有做到OP标题中所说的,而我能找到的最好的解决方案会导致元素跳动。 然后,我想到了一个办法:将元素设置为“固定”,检测水平滚动发生的时间,并将其切换为绝对定位。 以下是结果代码:

在Code Pen上查看它。

HTML

  <div class="blue">
    <div class="red">
    </div>
  </div>

CSS

:层叠样式表
/* Styling */
.blue, .red {
  border-style: dashed;
  border-width: 2px;
  padding: 2px;
  margin-bottom: 2px;
}

/* This will be out "vertical-fixed" element */
.red {
  border-color: red;
  height: 120px;
  position: fixed;
  width: 500px;
}

/* Container so we can see when we scroll */
.blue {
  border-color: blue;
  width: 50%;
  display: inline-block;
  height: 800px;
}

JavaScript

$(function () {
  var $document = $(document),
      left = 0,
      scrollTimer = 0;

  // Detect horizontal scroll start and stop.
  $document.on("scroll", function () {
    var docLeft = $document.scrollLeft();
    if(left !== docLeft) {
      var self = this, args = arguments;
      if(!scrollTimer) {
        // We've not yet (re)started the timer: It's the beginning of scrolling.
        startHScroll.apply(self, args);
      }
      window.clearTimeout(scrollTimer);
      scrollTimer = window.setTimeout(function () {
        scrollTimer = 0;
        // Our timer was never stopped: We've finished scrolling.
        stopHScroll.apply(self, args);
      }, 100);
      left = docLeft;
    }
  });

  // Horizontal scroll started - Make div's absolutely positioned.
  function startHScroll () {
    console.log("Scroll Start");
    $(".red")
    // Clear out any left-positioning set by stopHScroll.
    .css("left","")
    .each(function () {
      var $this = $(this),
          pos = $this.offset();
      // Preserve our current vertical position...
      $this.css("top", pos.top)
    })
    // ...before making it absolutely positioned.
    .css("position", "absolute");
  }

  // Horizontal scroll stopped - Make div's float again.
  function stopHScroll () {
    var leftScroll = $(window).scrollLeft();
    console.log("Scroll Stop");
    $(".red")
    // Clear out any top-positioning set by startHScroll.
    .css("top","")
    .each(function () {
      var $this = $(this), 
        pos = $this.position();
      // Preserve our current horizontal position, munus the scroll position...
      $this.css("left", pos.left-leftScroll);
    })
    // ...before making it fixed positioned.
    .css("position", "fixed");
  }
});

2
这是目前找到的最佳解决方案。即使在此解决方案发布4年后,似乎我们不得不使用它,只要Sticky在所有浏览器中没有得到适当的支持。 - Hedva
两年多后,仍然没有解决方案在视野中... 悲催的 CHROME Bug 报告可以在这里找到:https://bugs.chromium.org/p/chromium/issues/detail?id=702927 - Eytan

8

我来到这里是寻找一个类似的问题解决方案,即创建一个页脚栏,使其横跨整个窗口并位于(可变高度和宽度)内容下方。换句话说,让页脚在水平位置上看起来“固定”,但在垂直位置上保持其正常的文档流位置。在我的情况下,我将页脚文字右对齐,因此动态调整页脚的宽度适合我。以下是我的解决方案:

HTML

<div id="footer-outer">
<div id="footer">
    Footer text.
</div><!-- end footer -->
</div><!-- end footer-outer -->

CSS

#footer-outer
{
    width: 100%;
}
#footer
{
    text-align: right;
    background-color: blue;
    /* various style attributes, not important for the example */
}

CoffeeScript / JavaScript

(Using prototype.js).

class Footer
document.observe 'dom:loaded', ->
    Footer.width = $('footer-outer').getDimensions().width
Event.observe window, 'scroll', ->
    x = document.viewport.getScrollOffsets().left
    $('footer-outer').setStyle( {'width': (Footer.width + x) + "px"} )

编译后的结果为:

Footer = (function() {

  function Footer() {}

  return Footer;

})();

document.observe('dom:loaded', function() {
  return Footer.width = $('footer-outer').getDimensions().width;
});

Event.observe(window, 'scroll', function() {
  var x;
  x = document.viewport.getScrollOffsets().left;
  return $('footer-outer').setStyle({
    'width': (Footer.width + x) + "px"
  });
});

这在FireFox中表现得很好,在Chrome中表现也不错(有点抖动);我还没有尝试其他浏览器。

我还希望页脚以下的任何空白处都是不同的颜色,因此我添加了这个footer-stretch div:

HTML

...
</div><!-- end footer -->
<div id="footer-stretch"></div>
</div><!-- end footer-outer -->

CSS

#footer-outer
{
    height: 100%;
}
#footer-stretch
{
    height: 100%;
    background-color: #2A2A2A;
}

请注意,对于 #footer-stretch div 生效需要所有父元素(直到 body 元素及可能的 html 元素 - 不确定)具有固定高度(在本例中,高度 = 100%)。

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