Позиционирование элемента по вертикали, абсолютное по горизонтали

Вот чего я пытаюсь достичь:

Мне нужна кнопка, которая расположена на определенном расстоянии от правой стороны div и всегда находится на том же расстоянии от стороны div, независимо от размера области просмотра, но будет прокручиваться вместе с окном.

Таким образом, это всегда x пикселей от правой стороны div, но всегда y пикселей от верхней части порта просмотра.

Это возможно?


person Jimmy    schedule 21.07.2010    source источник


Ответы (3)


Расположите фиксированный элемент по горизонтали от другого элемента

(Примечание об отказе от ответственности: Предлагаемое здесь решение технически не является "absolute Horizontally", как указано в заголовке вопроса, но достиг того, что изначально хотел 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.fixed, а использовать два блока-обертки для установки горизонтального положения. div.positioner не необходим, если div.inflow имеет фиксированную ширину, поскольку левое поле div.fixed может быть установлено равным известной ширине контейнера. Однако, если вы хотите, чтобы контейнер имел ширину в процентах, вам понадобится div.positioner, чтобы сначала переместить div.fixed в правую сторону от div.inflow.

Изменить: в качестве интересного примечания, когда я устанавливаю overflow: hidden (если это необходимо) на div.inflow, это не влияет на то, что div с фиксированной позицией находится за пределами границ другого . Очевидно, фиксированной позиции достаточно, чтобы вынуть ее из контекста содержащего div для overflow.

person ScottS    schedule 21.07.2010
comment
Мое удовольствие (буквально было интересно понять) - person ScottS; 22.07.2010
comment
На самом деле это не работает так, как ожидалось. Как только появится горизонтальная полоса прокрутки и вы сможете прокручивать вправо, поле фиксированного положения не будет оставаться на том же расстоянии от div. Прокрутите страницу вправо: jsfiddle.net/tXXtL - person sparebytes; 24.09.2012
comment
@ Sparebytes - если это то, чего вы ожидали, то я согласен. Исходный OP просто искал способ расположить фиксированный элемент горизонтально от другого элемента. В его версии порт просмотра изменит размер (горизонтальная полоса прокрутки не появится). В конечном итоге этот элемент по-прежнему является fixed элементом, и на него не влияет прокрутка. Возможно, мне следует обновить заголовок вопроса, чтобы отразить это. - person ScottS; 25.09.2012
comment
@ Sparebytes - вместо того, чтобы изменить заголовок сообщения, я решил добавить к своему ответу отказ от ответственности, чтобы никто другой не был застигнут врасплох относительно того, чего он достиг. Спасибо, что обратили мое внимание на ваше ожидание, чтобы его можно было решить. - person ScottS; 25.09.2012
comment
@ScottS, рад, что вы обновили свой ответ. Я не думаю, что возможно иметь одно измерение fixed, а другое absolute только с помощью Css, javascript должен обновлять координаты при прокрутке. - person sparebytes; 28.09.2012

После долгих поисков (включая этот пост) я не смог найти решение, которое мне понравилось. Принятый ответ здесь не соответствует тому, что написано в заголовке OP, и лучшие решения, которые я мог найти, по общему признанию, привели к скачкообразным элементам. Затем меня осенило: нужно «зафиксировать» элемент, определить, когда происходит горизонтальная прокрутка, и переключить его, чтобы он стал абсолютно позиционированным. Вот полученный код:

Просмотреть его как кодовое перо.

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");
  }
});
person Grinn    schedule 07.08.2014
comment
Это лучшее решение, найденное на данный момент. Даже через 4 года после публикации этого решения. Похоже, мы должны работать с этим, пока Sticky не имеет надлежащей поддержки во всех браузерах - person Hedva; 24.10.2018
comment
2+ года спустя, и все еще нет исправлений на горизонте ... печальный отчет об ошибке CHROME доступен здесь - person Eytan; 27.12.2020

Я прибыл сюда в поисках решения аналогичной проблемы, которая заключалась в том, чтобы иметь панель нижнего колонтитула, которая охватывает ширину окна и находится под содержимым (переменной высоты и ширины). Другими словами, создайте впечатление, что нижний колонтитул «фиксирован» по отношению к своему горизонтальному положению, но сохраняет свое обычное положение в потоке документов по отношению к его вертикальному положению. В моем случае текст нижнего колонтитула был выровнен по правому краю, поэтому мне удалось динамически регулировать ширину нижнего колонтитула. Вот что я придумал:

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

(Используя 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;
}

Обратите внимание, что для работы div # footer-stretch все родительские элементы до элемента body (и, возможно, элемента html - не уверен) должны иметь фиксированную высоту (в данном случае height = 100%).

person Waz    schedule 27.06.2012