73 votes

Positionnement de l'élément fixe verticalement, absolu horizontalement

Voici ce que j'essaie d'accomplir :

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

Il est donc toujours à x pixels du côté droit de la division, mais toujours à y pixels du haut de la fenêtre d'affichage.

Est-ce possible ?

51voto

ScottS Points 37738

Positionner horizontalement un élément fixe en fonction d'un autre élément

( Note d'avertissement : La solution proposée ici n'est pas techniquement " absolus horizontalement comme l'indiquait le titre de la question, mais elle a permis d'obtenir ce que le PO souhaitait à l'origine, à savoir que l'élément à position fixe soit à une distance "X" du bord droit d'un autre élément, mais qu'il soit fixe dans son défilement vertical).

J'adore ces types de défis css. Comme une preuve de concept, oui, vous pouvez obtenir ce que vous désirez . Il se peut que vous deviez modifier certaines choses en fonction de vos besoins, mais voici quelques exemples de code html et css qui ont passé avec succès les tests de FireFox, IE8 et IE7 (IE6, bien sûr, n'a pas de code html et css). 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 définir le left o right du tout pour l'horizontale sur le div.fixed mais utilisez les deux divs d'habillage pour définir la position horizontale. Le site div.positioner es no nécessaire si le div.inflow est d'une largeur fixe, comme la marge gauche de l'écran d'accueil. div.fixed peut être fixé à la largeur connue du conteneur. Toutefois, si vous souhaitez que le conteneur ait une largeur en pourcentage, vous aurez besoin de l'attribut div.positioner pour pousser le div.fixed à droite de la div.inflow d'abord.

Editar: À titre d'information, lorsque j'ai défini overflow: hidden (si l'on doit le faire) sur le site de la div.inflow avait aucun effet sur la position fixe d'être en dehors des frontières de l'autre. Apparemment, la position fixe est suffisante pour la faire sortir du contexte de la div qui la contient pour les raisons suivantes overflow .

13voto

Grinn Points 1966

Après de nombreuses recherches (dont ce billet), je n'ai pas trouvé de solution qui me convienne. La réponse acceptée ici ne fait pas ce que le titre de l'OP indique, et les meilleures solutions que j'ai pu trouver ont abouti à des éléments qui sautent. Puis, j'ai eu une idée : faire en sorte que l'élément soit "fixe", détecter quand un défilement horizontal se produit, et le faire basculer pour qu'il soit positionné de manière absolue. Voici le code qui en résulte :

Considérez-le comme un 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");
  }
});

8voto

Waz Points 138

Je suis arrivé ici en cherchant une solution à un problème similaire, à savoir une barre de bas de page qui s'étend sur toute la largeur de la fenêtre et se trouve sous le contenu (de hauteur et de largeur variables). En d'autres termes, il faut donner l'impression que le pied de page est "fixe" en ce qui concerne sa position horizontale, mais qu'il conserve sa position normale dans le flux de documents en ce qui concerne sa position verticale. Dans mon cas, le texte du pied de page était aligné à droite, ce qui m'a permis d'ajuster dynamiquement la largeur du pied de page. Voici la solution que j'ai trouvée :

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 se compile en :

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 (il y a un peu d'instabilité) ; je n'ai pas essayé les autres navigateurs.

Je voulais aussi que l'espace libre sous le pied de page soit d'une couleur différente, j'ai donc 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 %).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X