web-dev-qa-db-fra.com

Position fixe mais relative au conteneur

J'essaie de corriger une div afin qu'elle reste toujours en haut de l'écran, en utilisant:

position: fixed;
top: 0px;
right: 0px;

Cependant, la div est à l'intérieur d'un conteneur centré. Lorsque j'utilise position:fixed, il corrige la variable div par rapport à la fenêtre du navigateur, par exemple en la plaçant sur le côté droit du navigateur. Au lieu de cela, il devrait être fixé par rapport au conteneur.

Je sais que position:absolute peut être utilisé pour corriger un élément par rapport à div, mais lorsque vous faites défiler la page, l'élément disparaît et ne reste pas en haut comme avec position:fixed.

Y at-il un hack ou une solution de contournement pour y parvenir?

539
Zach Nicodemous

Réponse courte: non. (C'est maintenant possible avec la transformation CSS. Voir l'édition ci-dessous)

Réponse longue: Le problème avec l'utilisation du positionnement "fixe" est que cela prend l'élément du flux. ainsi, il ne peut pas être repositionné par rapport à son parent car c'est comme s'il n'en avait pas. Si, toutefois, le conteneur a une largeur fixe connue, vous pouvez utiliser quelque chose comme:

#fixedContainer {
  position: fixed;
  width: 600px;
  height: 200px;
  left: 50%;
  top: 0%;
  margin-left: -300px; /*half the width*/
}

http://jsfiddle.net/HFjU6/1/

Modifier (03/2015):

Ce sont des informations obsolètes. Il est maintenant possible de centrer le contenu d'une taille dynamique (horizontalement et verticalement) à l'aide de la magie de la transformation CSS3. Le même principe s'applique, mais au lieu d'utiliser margin pour décaler votre conteneur, vous pouvez utiliser translateX(-50%). Cela ne fonctionne pas avec l'astuce de marge ci-dessus parce que vous ne savez pas combien le compenser sauf si la largeur est fixe et que vous ne pouvez pas utiliser de valeurs relatives (comme 50%) car ce sera relatif au parent et non à l'élément c'est appliqué à. transform se comporte différemment. Ses valeurs sont relatives à l'élément auquel elles sont appliquées. Ainsi, 50% pour transform signifie la moitié de la largeur de l'élément, tandis que 50% pour la marge correspond à la moitié de la largeur du parent. Ceci est une solution IE9 +

En utilisant un code similaire à l'exemple ci-dessus, j'ai recréé le même scénario en utilisant une largeur et une hauteur complètement dynamiques:

.fixedContainer {
    background-color:#ddd;
    position: fixed;
    padding: 2em;
    left: 50%;
    top: 0%;
    transform: translateX(-50%);
}

Si vous voulez qu'il soit centré, vous pouvez le faire aussi:

.fixedContainer {
    background-color:#ddd;
    position: fixed;
    padding: 2em;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}

Démos:

jsFiddle: Centré uniquement horizontalement
jsFiddle: Centré à la fois horizontalement et verticalement
Le crédit original va à l'utilisateur aaronk6 pour me l'avoir signalé dans cette réponse

358
Joseph Marikle

En fait, cela est possible et la réponse acceptée ne traite que de la centralisation, ce qui est assez simple. De plus, vous n'avez vraiment pas besoin d'utiliser JavaScript.

Cela vous permettra de faire face à n'importe quel scénario:

Configurez tout comme si vous vouliez positionner: absolute dans une position: conteneur relatif, puis créer un nouveau div à position fixe dans le div avec position: absolute, mais ne not pas définir ses propriétés top et left. Il sera ensuite corrigé où vous le souhaitez, par rapport au conteneur.

Par exemple:

/* Main site body */
.wrapper {
    width: 940px;
    margin: 0 auto;
    position: relative; /* Ensure absolute positioned child elements are relative to this*/
}

/* Absolute positioned wrapper for the element you want to fix position */
.fixed-wrapper {
    width: 220px;
    position: absolute;
    top: 0;
    left: -240px; /* Move this out to the left of the site body, leaving a 20px Gutter */
}

/* The element you want to fix the position of */
.fixed {
    width: 220px;
    position: fixed;
    /* Do not set top / left! */
}
<div class="wrapper">
    <div class="fixed-wrapper">
        <div class="fixed">
            Content in here will be fixed position, but 240px to the left of the site body.
        </div>
    </div>
</div>

Malheureusement, j'espérais que ce fil pourrait résoudre mon problème avec le rendu WebKit d'Android par boîte-ombre rendant les pixels flous en tant que marges sur les éléments à position fixe, mais il semble que ce soit un bug.
Quoi qu'il en soit, j'espère que cela aide!

157
Graeme Blackwood

Oui, selon les spécifications, il y a un moyen.

Bien que je convienne que la réponse de Graeme Blackwood devrait être acceptée, car elle résout pratiquement le problème, il convient de noter qu'un élément fixe peut être positionné par rapport à son conteneur.

J'ai remarqué par accident que lors de l'application

-webkit-transform: translateZ(0);

pour le corps, il a fait un enfant fixe par rapport à lui (au lieu de la fenêtre d'affichage). Ainsi, mes propriétés left et top des éléments fixes étaient maintenant relatives au conteneur.

J'ai donc fait des recherches et découvert que le problème avait déjà été traité par Eric Meyer et même si cela ressemblait à un "truc", il s'avère que cela fait partie du cahier des charges:

Pour les éléments dont la présentation est régie par le modèle de boîte CSS, toute valeur autre que néant pour la transformation entraîne la création à la fois d'un contexte d'empilement et un bloc contenant. L'objet agit comme un contenant un bloc pour les descendants fixes.

http://www.w3.org/TR/css3-transforms/

Ainsi, si vous appliquez une transformation à un élément parent, celui-ci deviendra le bloc conteneur.

Mais...

Le problème est que l'implémentation semble boguée/créative, car les éléments cessent également de se comporter comme des éléments corrigés (même si ce bit ne semble pas faire partie de la spécification).

Le même comportement se retrouvera dans Safari, Chrome et Firefox, mais pas dans IE11 (où l'élément corrigé restera toujours corrigé).

Une autre chose intéressante (non documentée) est que, lorsqu'un élément fixe est contenu dans un élément transformé, alors que ses propriétés top et left sont désormais liées au conteneur, en respectant la propriété box-sizing, son contexte de défilement s'étend au-delà de la bordure de l'élément. comme si box-sizing était défini sur border-box. Pour certains créatifs, cela pourrait devenir un jouet :)

TEST

121

La réponse est oui, tant que vous ne définissez pas left: 0 ou right: 0 après avoir défini la position div sur fixed.

http://jsfiddle.net/T2PL5/85/

Commander la barre latérale div. Il est corrigé, mais lié au parent, pas au point de vue de la fenêtre.

body { background: #ccc; }

.wrapper {
    margin: 0 auto;
    height: 1400px;
    width: 650px;
    background: green;
}

.sidebar {
    background-color: #ddd;
    float: left;
    width: 300px;
    height: 100px;
    position: fixed;
}

.main {
    float: right;
    background-color: yellow;
    width: 300px;
    height: 1400px;
}

<div class="wrapper">wrapper
    <div class="sidebar">sidebar</div>
    <div class="main">main</div>
</div>
55
Shadow_boi

position: sticky est un nouveau moyen de positionner des éléments de concept similaire au position: fixed. La différence est qu'un élément avec position: sticky se comporte comme position: relative dans son parent, jusqu'à ce qu'un seuil de décalage donné soit atteint dans la fenêtre d'affichage. 

Dans Chrome 56 (version bêta de décembre 2016, stable en janvier 2017), position: post-it est de retour.

https://developers.google.com/web/updates/2016/12/position-sticky

Plus de détails sont dans Collez vos atterrissages! position: sticky débarque dans WebKit.

23
PoseLab

J'ai créé ce plugin jQuery pour résoudre un problème similaire: j'avais un conteneur centré (données tabulaires), et je voulais que l'en-tête se fixe en haut de la page lorsque la liste défilait, mais je voulais qu'il soit ancré à les données tabulaires de sorte que ce soit où je mets le conteneur (centré, gauche, droite) et que je lui permette également de se déplacer à gauche et à droite avec la page lorsqu’il fait défiler horizontalement.

Voici le lien vers ce plugin jQuery qui pourrait résoudre ce problème:

https://github.com/bigspotteddog/ScrollToFixed

La description de ce plugin est la suivante:

Ce plugin est utilisé pour fixer des éléments en haut de la page, si l'élément aurait défilé verticalement; Cependant, cela permet à l'élément de continuer à se déplacer à gauche ou à droite avec le défilement horizontal.

Avec une option marginTop, l'élément cessera de se déplacer verticalement vers le haut une fois que le défilement vertical a atteint la position cible. mais l'élément continuera à se déplacer horizontalement lorsque la page défilera à gauche ou à droite. Une fois que la page a été rétablie et que la position cible a été rétablie, l'élément est restauré à sa position d'origine sur la page.

Ce plugin a été testé dans Firefox 3/4, Google Chrome 10/11, Safari 5 et Internet Explorer 8/9.

Utilisation pour votre cas particulier:

<script src="scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery-scrolltofixed-min.js" type="text/javascript"></script>

$(document).ready(function() {
    $('#mydiv').scrollToFixed();
});
18
bigspotteddog

Il suffit de sortir les styles haut et gauche de la position fixe div. Voici un exemple

<div id='body' style='height:200%; position: absolute; width: 100%; '>
    <div id='parent' style='display: block; margin: 0px auto; width: 200px;'>
        <div id='content' style='position: fixed;'>content</div>
    </div>
</div> 

La division #content sera assise où la division parent est assise, mais y sera fixée. 

17
hobberwickey

Je devais faire cela avec une publicité que mon client voulait placer en dehors de la zone de contenu. J'ai simplement fait ce qui suit et cela a fonctionné à merveille!

<div id="content" style="position:relative; width:750px; margin:0 auto;">
  <div id="leftOutsideAd" style="position:absolute; top:0; left:-150px;">
    <a href="#" style="position:fixed;"><img src="###" /></a>
  </div>
</div>
12
Eric K

Deux éléments HTML et CSS pur (navigateurs modernes)

Voir cet exemple jsFiddle. Redimensionnez et voyez comment les éléments fixes se déplacent même avec les éléments flottants dans lesquels ils se trouvent. Utilisez la barre de défilement la plus interne pour voir comment le défilement fonctionnerait sur un site (les éléments fixes resteraient fixes).

Comme beaucoup de personnes l'ont indiqué, l'une des clés ne définit aucun paramètre de position sur l'élément fixed (aucune valeur top, right, bottom ou left).

Nous plaçons plutôt tous les éléments fixes (notez comment la dernière case en contient quatre) en premier dans la case où ils doivent être positionnés, comme suit:

<div class="reference">
  <div class="fixed">Test</div>
  Some other content in.
</div>

Ensuite, nous utilisons margin-top et margin-left pour les "déplacer" par rapport à leur conteneur, comme dans le cas de ce CSS:

.fixed {
    position: fixed;
    margin-top: 200px; /* Push/pull it up/down */
    margin-left: 200px; /* Push/pull it right/left */
}

Notez que, comme les éléments fixed ignorent tous les autres éléments de présentation, le conteneur final dans notre violon - peut avoir plusieurs éléments fixed et avoir toujours tous ces éléments liés au coin supérieur gauche. Mais cela n’est vrai que si elles sont toutes placées en premier dans le conteneur, comme le montre ce violon comparatif, que si elles sont dispersées dans le contenu du conteneur, le positionnement devient peu fiable .

Que le wrapper soit statique , relatif ou absolu dans le positionnement, peu importe.

7
ScottS

Vous pouvez utiliser la propriété position: sticky. 

Voici un exemple CODEPEN démontrant l’utilisation et comment il diffère de position: fixed

Son comportement est expliqué ci-dessous:

  1. Un élément avec une position collante est positionné en fonction de la position de défilement de l'utilisateur. Il agit essentiellement comme position: relative jusqu'à ce qu'un élément défile au-delà d'un décalage spécifique, auquel cas il se transforme en position: fixed. Quand il fait défiler en arrière, il revient à sa position précédente (relative).

  2. Il affecte le flux des autres éléments de la page, c’est-à-dire occupe un espace spécifique sur la page (comme position: relative).

  3. S'il est défini dans un conteneur, il est positionné par rapport à ce conteneur. Si le conteneur présente un débordement (défilement), en fonction du décalage de défilement, il se transforme en position: fixe.

Donc, si vous souhaitez obtenir la fonctionnalité fixe mais à l’intérieur d’un conteneur, utilisez sticky.

6
Pransh Tiwari

Vous pouvez essayer mon plugin jQuery, FixTo .

Usage:

$('#mydiv').fixTo('#centeredContainer');
3
Burak

Une autre solution étrange pour obtenir une position fixe relative consiste à convertir votre conteneur en iframe. Ainsi, votre élément fixe peut être fixé à la fenêtre du conteneur et non à la page entière.

2
Beto Aveiga

Avec du CSS pur, vous ne pouvez pas le faire. au moins je n'ai pas. Cependant, vous pouvez le faire très simplement avec jQuery. Je vais expliquer mon problème et avec un petit changement, vous pouvez l'utiliser.

Donc, pour commencer, je voulais que mon élément ait un sommet fixe (du haut de la fenêtre) et un composant de gauche à hériter de l'élément parent (car l'élément parent est centré). Pour définir le composant de gauche, placez simplement votre élément dans le parent et définissez position:relative pour l'élément parent.

Ensuite, vous devez savoir quelle est la valeur depuis le haut de votre élément lorsque la barre de défilement est au-dessus (y défilement zéro); il y a encore deux options. Tout d’abord, c’est statique (un certain nombre) ou vous devez le lire à partir de l’élément parent.

Dans mon cas, c'est 150 pixels du haut statique. Donc, quand vous voyez 150, c'est combien l'élément du haut quand nous n'avons pas fait défiler.

CSS

#parent-element{position:relative;}
#promo{position:absolute;}

jQuery

$(document).ready(function() { //This check window scroll bar location on start
    wtop=parseInt($(window).scrollTop());
    $("#promo").css('top',150+wtop+'px');

});
$(window).scroll(function () { //This is when the window is scrolling
    wtop=parseInt($(window).scrollTop());
    $("#promo").css('top',150+wtop+'px');
});
2
Mr Br

J'ai créé un jsfiddle pour montrer comment cela fonctionne avec transform.

HTML

<div class="left">
    Content
</div>
<div class="right">
<div class="fixedContainer">
    X
</div>
    Side bar
</div>

CSS

body {
  margin: 0;
}
.left {
  width: 77%;
  background: teal;
  height: 2000px;
}
.right {
  width: 23%;
  background: yellow;
  height: 100vh;
  position: fixed;
  right: 0;
  top: 0;
}
.fixedContainer {
    background-color:#ddd;
    position: fixed;
    padding: 2em;
    //right: 0;
    top: 0%;
    transform: translateX(-100px);
}

jQuery

$('.fixedContainer').on('click', function() {
    $('.right').animate({'width': '0px'});
  $('.left').animate({'width': '100%'});
});

https://jsfiddle.net/bx6ktwnn/1/

1
Wen

J'ai le même problème, l'un des membres de notre équipe me donne une solution .Pour permettre à la position de div div et par rapport à d'autres div, notre solution consiste à utiliser un conteneur père pour envelopper le correctif div et le défilement div. 

<div class="container">
  <div class="scroll"></div>
  <div class="fix"></div>
</div>

css

.container {
  position: relative;
  flex:1;
  display:flex;
}

.fix {
  prosition:absolute;
}
1
Jay0Lu

C'est facile (selon HTML ci-dessous)

L'astuce consiste à NE PAS utiliser top ou left sur l'élément (div) avec "position: fixed;" . Si elles ne sont pas spécifiées, l'élément "fixed content" apparaîtra RELATIVE à l'élément englobant (le div avec " position: relative; ") INSTEAD OF par rapport à la fenêtre du navigateur !!!

<div id="divTermsOfUse" style="width:870px; z-index: 20; overflow:auto;">
    <div id="divCloser" style="position:relative; left: 852px;">
        <div style="position:fixed; z-index:22;">
            <a href="javascript:hideDiv('divTermsOfUse');">
                <span style="font-size:18pt; font-weight:bold;">X</span>
            </a>
        </div>
    </div>
    <div>  <!-- container for... -->
         lots of Text To Be Scrolled vertically...
         bhah! blah! blah!
    </div>
</div>

Ci-dessus m'a permis de localiser un bouton "X" de fermeture en haut de beaucoup de texte dans une div avec défilement vertical. Le "X" reste en place (il ne se déplace pas avec le texte défilé, mais il se déplace également vers la gauche ou la droite avec le conteneur div qui le entoure lorsque l'utilisateur redimensionne la largeur de la fenêtre du navigateur! Il est donc "fixé" verticalement, mais positionné par rapport à l'élément d'enceinte horizontalement!

Avant que je ne travaille, le "X" défilait et disparaissait lorsque je faisais défiler le contenu du texte. 

Toutes mes excuses pour ne pas avoir fourni la fonction javascript hideDiv (), mais cela allongerait inutilement cette publication. J'ai choisi de le garder le plus court possible.

1
Bruce Allen

Mon projet est un modèle .NET ASP Core 2 MVC Angular 4 avec Bootstrap 4. L'ajout de "sticky-top" au composant principal de l'application html (c'est-à-dire app.component.html) à la première ligne a fonctionné, comme suit:

<div class='row sticky-top'>
    <div class='col-sm-12'>
        <nav-menu-top></nav-menu-top>
    </div>
</div>
<div class="row">
    <div class='col-sm-3'>
        <nav-menu></nav-menu>
    </div>
    <div class='col-sm-9 body-content'>
        <router-outlet></router-outlet>
    </div>
</div>

Est-ce la convention ou est-ce que j'ai trop simplifié?

0
Adam Cox
/* html */

/* this div exists purely for the purpose of positioning the fixed div it contains */
<div class="fix-my-fixed-div-to-its-parent-not-the-body">

     <div class="im-fixed-within-my-container-div-zone">
          my fixed content
     </div>

</div>



/* css */

/* wraps fixed div to get desired fixed outcome */
.fix-my-fixed-div-to-its-parent-not-the-body 
{
    float: right;
}

.im-fixed-within-my-container-div-zone
{
    position: fixed;
    transform: translate(-100%);
}
0
Carol McKay

J'ai fait quelque chose comme ça il y a quelque temps. J'étais assez nouveau en JavaScript, alors je suis sûr que vous pouvez faire mieux, mais voici un point de départ:

function fixxedtext() {
    if (navigator.appName.indexOf("Microsoft") != -1) {
        if (document.body.offsetWidth > 960) {
            var width = document.body.offsetWidth - 960;
            width = width / 2;
            document.getElementById("side").style.marginRight = width + "px";
        }
        if (document.body.offsetWidth < 960) {
            var width = 960 - document.body.offsetWidth;
            document.getElementById("side").style.marginRight = "-" + width + "px";
        }
    }
    else {
        if (window.innerWidth > 960) {
            var width = window.innerWidth - 960;
            width = width / 2;
            document.getElementById("side").style.marginRight = width + "px";
        }
        if (window.innerWidth < 960) {
            var width = 960 - window.innerWidth;
            document.getElementById("side").style.marginRight = "-" + width + "px";
        }
    }
    window.setTimeout("fixxedtext()", 2500)
}

Vous aurez besoin de définir votre largeur, puis il obtient la largeur de la fenêtre et modifie la marge toutes les quelques secondes. Je sais que c'est lourd, mais ça marche.

0
webLacky3rdClass

C'est possible si vous utilisez JavaScript. Dans ce cas, le plugin jQuery Sticky-Kit:

0
Paz Aricha