Élément de Position fixé verticalement, absolu horizontalement

Voici ce que j'essaie d'accomplir:

J'ai besoin d'un bouton qui est positionné à une certaine distance du côté droit d'une div, et qui est toujours à la même distance du côté de la div, quelle que soit la taille de la fenêtre, mais qui défilera avec la fenêtre.

Il s'agit donc de x pixels du côté droit de la div à tout moment, mais de y pixels du haut du port de vue à tout moment.

Est-ce possible?

58
demandé sur ScottS 2010-07-21 23:45:04

3 réponses

Positionner L'Élément Fixe Horizontalement En Fonction D'Un Autre Élément

(avertissement Note: la solution proposée ici n'est pas techniquement "absolu horizontalement "comme le titre de la question l'a indiqué, mais a réalisé ce que l'OP voulait à l'origine, l'élément de position fixe étant" X " distance du bord droit d'un autre mais fixé dans son défilement vertical.)

J'adore ces types de défis css. Comme preuve de concept, Oui, vous pouvez obtenir quoi vous désirez. Vous devrez peut-être modifier certaines choses pour vos besoins, mais voici quelques exemples de html et css qui ont passé FireFox, IE8 et IE7 (IE6, bien sûr, n'a pas 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 (bordures et toutes les dimensions pour la démonstration):

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

La clé est de ne pas mettre les left ou right à l'horizontale sur la div.fixed, mais utiliser les deux wrapper divs pour régler la position horizontale. Le div.positioner est pas nécessaire si l' div.inflow est une largeur fixe, car la marge gauche du div.fixed peut être définie sur la largeur connue du conteneur. Cependant, si vous désirez que container ait une largeur de pourcentage, alors vous aurez besoin du div.positioner pour pousser le div.fixed sur le côté droit du div.inflow en premier.

Edit: comme une note de côté intéressante, quand je mets overflow: hidden (devrait-on avoir besoin de le faire) sur le div.inflow n'avait Aucun effet sur la position fixe div étant en dehors des limites de l'autre. Apparemment la position fixe est assez pour le sortir du contexte du div contenant pour overflow.

43
répondu ScottS 2016-06-19 15:25:51

Je suis arrivé ici à la recherche d'une solution à un problème similaire, qui était d'avoir une barre de pied de page qui s'étend sur la largeur de la fenêtre et se trouve en dessous du contenu (hauteur et largeur variables). En d'autres termes, faire apparaître que le pied de page est "fixe" par rapport à sa position horizontale, mais conserve sa position normale dans le flux du document par rapport à sa position verticale. Dans mon cas, j'avais le texte de pied de page aligné à droite, donc il a fonctionné pour moi d'ajuster dynamiquement la largeur du pied de page. Voici ce que je suis venu avec:

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

(en utilisant 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"} )

Qui compile dans:

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

Cela fonctionne bien dans FireFox, et assez bien dans Chrome (c'est un peu nerveux); je n'ai pas essayé d'autres navigateurs.

Je voulais aussi que tout espace libre sous le pied de page soit d'une couleur différente, alors j'ai ajouté ceci 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;
}

Notez que pour que le div # footer-stretch fonctionne, tous les éléments parents jusqu'à l'élément body (et éventuellement l'élément html - pas sûr) doivent avoir une hauteur fixe (dans ce cas, height = 100%).

7
répondu Waz 2012-07-05 20:53:32

Après avoir beaucoup creusé (y compris ce post), je n'ai pas pu trouver une solution qui m'a plu. La réponse acceptée ici ne fait pas ce que le titre du PO lisait, et les meilleures solutions que j'ai pu trouver ont certes donné lieu à des éléments nerveux. Ensuite, il m'a frappé: avoir l'élément "fixe", détecter quand un défilement horizontal se produit, et le mettre à être absolument positionné. Voici le code résultant:

Voir comme un Code Stylo.

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");
  }
});
7
répondu Grinn 2014-08-07 18:23:19