Positionselement vertikal fixiert, absolut horizontal

77

Folgendes versuche ich zu erreichen:

Ich benötige eine Schaltfläche, die in einem bestimmten Abstand von der rechten Seite eines Div positioniert ist und unabhängig von der Größe des Ansichtsfensters immer den gleichen Abstand von der Seite des Div hat, aber mit dem Fenster gescrollt wird.

Es sind also immer x Pixel von der rechten Seite des Divs, aber immer y Pixel von der Oberseite des Ansichtsfensters.

Ist das möglich?

Jimmy
quelle

Antworten:

54

Positionieren Sie das feste Element horizontal basierend auf einem anderen Element

( Haftungsausschluss Hinweis : Die hier angebotene Lösung ist technisch gesehen nicht " absolut horizontal ", wie im Fragentitel angegeben, sondern hat das erreicht, was das OP ursprünglich wollte. Das Element mit fester Position sollte "X" vom rechten Rand eines anderen entfernt sein, aber in seiner Position fixiert sein vertikale Schriftrolle.)

Ich liebe diese Art von CSS-Herausforderungen. Als Proof of Concept können Sie ja bekommen, was Sie wollen . Möglicherweise müssen Sie einige Dinge an Ihre Bedürfnisse anpassen, aber hier sind einige Beispiele für HTML und CSS, die FireFox, IE8 und IE7 bestanden haben (IE6 natürlich nicht 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 (Grenzen und alle Dimensionen zur Demonstration):

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;
}

Der Schlüssel ist, nicht die leftoder rightüberhaupt nicht für die Horizontale auf der zu setzen, div.fixedsondern die horizontalen Positionen mit den beiden Wrapper-Divs einzustellen. Das div.positionerwird nicht benötigt, wenn div.inflowes sich um eine feste Breite handelt, da der linke Rand des auf die div.fixedbekannte Breite des Containers eingestellt werden kann. Wenn Sie jedoch möchten, dass der Container eine prozentuale Breite hat, müssen Sie div.positionerden div.fixedauf die rechte Seite des div.inflowersten schieben .

Edit: Als interessante Randnotiz, wenn ich gesetzt overflow: hidden(sollte man Notwendigkeit , das zu tun) auf der div.inflowhatte keine Auswirkungen auf die feste Position div außerhalb der Grenzen des anderen ist. Anscheinend reicht die feste Position aus, um sie aus dem Kontext des enthaltenen Div herauszunehmen overflow.

ScottS
quelle
5
Es war mir ein Vergnügen (im wahrsten
Sinne des
11
Es funktioniert nicht wie erwartet. Sobald es eine horizontale Bildlaufleiste gibt und Sie nach rechts scrollen können, bleibt das Feld für die feste Position nicht mehr gleich weit vom Div entfernt. Scrollen
Sie
@ sparebytes - wenn du das erwartet hast, dann stimme ich zu. Das ursprüngliche OP suchte nur nach einer Möglichkeit, das feste Element horizontal vom anderen Element zu positionieren. In seiner Version würde sich die Größe des Ansichtsfensters ändern (es würde keine horizontale Bildlaufleiste angezeigt). Das Element ist letztendlich immer noch ein fixedElement und bleibt vom Scrollen unberührt. Vielleicht sollte ich den Fragentitel aktualisieren, um dies widerzuspiegeln.
ScottS
@ sparebytes - Anstatt den Titel des Beitrags zu ändern, habe ich meiner Antwort einen Haftungsausschluss hinzugefügt, damit niemand anderes überrascht wird, was damit erreicht wird. Vielen Dank, dass Sie mich auf Ihre Erwartungen aufmerksam gemacht haben, damit sie angesprochen werden können.
ScottS
3
@ScottS, ich bin froh, dass Sie Ihre Antwort aktualisiert haben. Ich denke nicht, dass es möglich ist, eine Dimension fixedund die andere nur absolutemit CSS zu haben. Javascript muss die Koordinaten beim Scrollen aktualisieren.
Ersatzbytes
13

Nach langem Graben (einschließlich dieses Beitrags) konnte ich keine Lösung finden, die mir gefiel. Die hier akzeptierte Antwort macht nicht das, was der Titel des OP lautete, und die besten Lösungen, die ich finden konnte, führten zugegebenermaßen zu nervösen Elementen. Dann traf es mich: Lassen Sie das Element "fixieren", erkennen Sie, wann eine horizontale Schriftrolle auftritt, und schalten Sie es auf absolut positioniert. Hier ist der resultierende Code:

Zeigen Sie es als Codestift an.

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");
  }
});
Grinn
quelle
1
Dies ist die bisher beste Lösung. Auch 4 Jahre nachdem diese Lösung veröffentlicht wurde. Scheint, wir müssen damit arbeiten, solange Sticky nicht in allen Browsern die richtige Unterstützung hat
Hedva
8

Ich bin hier angekommen und habe nach einer Lösung für ein ähnliches Problem gesucht, nämlich eine Fußzeilenleiste, die sich über die Breite des Fensters erstreckt und unter dem Inhalt (variable Höhe und Breite) liegt. Mit anderen Worten, lassen Sie es so aussehen, als ob die Fußzeile in Bezug auf ihre horizontale Position "fest" ist, aber ihre normale Position im Dokumentenfluss in Bezug auf ihre vertikale Position beibehält. In meinem Fall war der Fußzeilentext rechtsbündig ausgerichtet, sodass ich die Breite der Fußzeile dynamisch anpassen konnte. Folgendes habe ich mir ausgedacht:

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

(Verwenden von 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"} )

was kompiliert in:

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"
  });
});

Dies funktioniert gut in FireFox und ziemlich gut in Chrome (es ist ein wenig nervös); Ich habe keine anderen Browser ausprobiert.

Ich wollte auch, dass jeder freie Platz unter der Fußzeile eine andere Farbe hat, also fügte ich dieses footer-stretchdiv hinzu :

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;
}

Beachten Sie, dass alle übergeordneten Elemente bis zum body-Element (und möglicherweise das HTML-Element - nicht sicher) eine feste Höhe haben müssen (in diesem Fall height = 100%), damit das # footer-align div funktioniert.

Waz
quelle