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


78

Ось що я намагаюся досягти:

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

Отже, це x пікселів від правої сторони div у будь-який час, але y пікселів від верхньої частини порту перегляду завжди.

Чи можливо це?

Відповіді:


54

Розташуйте закріплений елемент горизонтально на основі іншого елемента

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

Редагувати: Як цікаве побічне зауваження, коли я встановлював overflow: hidden(якщо це потрібно зробити), параметр div.inflowніяк не впливав на те, що div з фіксованою позицією знаходився поза межами іншого. Очевидно, фіксованої позиції досить, щоб вивести її з контексту div, що містить overflow.


5
Моє задоволення (буквально, це було весело з’ясувати)
ScottS

11
Насправді це працює не так, як очікувалося. Як тільки з'явиться горизонтальна смуга прокрутки, і ви зможете прокрутити праворуч, поле фіксованого положення не буде залишатися на тій самій відстані від div. Прокрутіть праворуч на цій сторінці: jsfiddle.net/tXXtL
запасні байти

@ sparebytes - якщо це те, чого ви очікували, то я згоден. Оригінальний ОП просто шукав спосіб, як закріпити елемент, розташований горизонтально від іншого елемента. У його версії порт перегляду змінює розмір (горизонтальна смуга прокрутки не відображатиметься). Елемент, як і раніше, все ще є fixedелементом і на нього не впливає прокрутка. Можливо, мені слід оновити назву запитання, щоб це відобразило.
ScottS

@ sparebytes - Замість того, щоб змінити заголовок на допис, я вирішив додати до моєї відповіді відмову від відповідальності, щоб ніхто інший не здивувався, чого він досяг. Дякуємо, що звернули мою увагу на ваші очікування, щоб вони могли бути реалізовані.
ScottS

3
@ScottS, радий, що ти оновив свою відповідь. Я не думаю, що можна мати один вимір, fixedа інший - лише за absoluteдопомогою Css, javascript повинен оновити координати при прокрутці.
запасні байти

14

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

Розгляньте це як кодову ручку.

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,

Через 2+ роки, і досі немає виправлення на горизонті ... сумний звіт про помилку CHROME доступний тут
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

(Використовуючи 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-stretchdiv:

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%).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.