821 votes

Position fixe mais relative au conteneur

J'essaie de réparer un div pour qu'il soit toujours collé en haut de l'écran, en utilisant :

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

Toutefois, le div est à l'intérieur d'un conteneur centré. Lorsque j'utilise position:fixed il fixe le div par rapport à la fenêtre du navigateur, de façon à ce qu'il soit contre le côté droit du navigateur. Au lieu de cela, il doit être fixe par rapport au conteneur.

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

Existe-t-il une astuce ou une solution de contournement pour y parvenir ?

0 votes

"Tether est une bibliothèque d'interface utilisateur de bas niveau qui peut être utilisée pour positionner tout élément sur une page à côté de tout autre élément." github.com/shipshapecode/tether + Démos/Docs à tether.io

499voto

Joseph Marikle Points 25280

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

Réponse longue : Le problème de l'utilisation du positionnement "fixe" est qu'il prend l'élément hors du flux . il ne peut donc 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 et 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/

Edit (03/2015) :

Cette information est dépassée. Il est désormais 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 la marge pour décaler votre conteneur, vous pouvez utiliser translateX(-50%) . Cela ne fonctionne pas avec l'astuce de la marge ci-dessus car vous ne savez pas de combien la décaler, à moins que la largeur soit fixe et que vous ne puissiez pas utiliser des valeurs relatives (comme 50% ) car il sera relatif au parent et non à l'élément auquel il est appliqué. transform se comporte différemment. Ses valeurs sont relatives à l'élément auquel elles sont appliquées. Ainsi , 50% para transform signifie la moitié de la largeur de l'élément, tandis que 50% pour la marge est la moitié de la largeur du parent. Il s'agit d'une Solution pour IE9

En utilisant un code similaire à celui de 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 aussi le faire :

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

Démonstrations :

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

0 votes

Ça a très bien marché pour moi. Bien que j'avais besoin de la mienne à gauche d'un div déjà centré et non fixé, j'ai dû diminuer la marge de gauche jusqu'à ce qu'elle soit alignée. Non reste aligné quelle que soit la largeur de la fenêtre. Merci. +1

10 votes

Joseph, tu sais pourquoi ? position:fixed sans préciser top o left parfois fonctionne ? Certains navigateurs semblent placer par défaut l'élément à l'endroit où il se trouverait normalement, s'il avait un positionnement normal. stackoverflow.com/questions/8712047/

3 votes

Qu'en est-il sans hauteur et largeur fixes ? Dans mon cas, je n'ai donné aucun signal de largeur à aucun conteneur, même jusqu'à la balise body. Quelle solution me direz-vous de faire ?

233voto

Graeme Blackwood Points 740

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

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

Configurez tout comme vous le feriez pour positionner : absolute à l'intérieur d'un conteneur position : relative, puis créez une nouvelle div à position fixe à l'intérieur de la div avec position: absolute mais ne no définir ses propriétés haut et gauche. Il sera alors fixé 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 de discussion pourrait résoudre mon problème avec le système Android. WebKit rendre les pixels du flou de l'ombre de la boîte comme des marges sur les éléments à position fixe, mais il semble que ce soit un bug.
En tout cas, j'espère que cela vous aidera !

2 votes

Pas tout à fait TOUT le scénario mais c'est un bon début. S'il y a beaucoup d'espace sous .wrapper, votre .fixed-wrapper se terminera en bas du parent, mais votre élément .fixed continuera à sortir des deux conteneurs et à s'insérer dans tout contenu situé en dessous. Comme je l'ai dit, c'est un bon début, pas parfait, mais je ne vois pas comment cela peut être accompli sans un peu de js.

4 votes

Cependant, cela ne joue pas en faveur d'une conception fluide.

5 votes

J'ai essayé de faire cela, mais lorsque je fais défiler vers le bas, l'en-tête que j'avais appliqué de manière fixe (avec un parent absolu auquel le parent était relatif) ne se déplace pas lorsque je fais défiler.

181voto

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 qu'en appliquant

-webkit-transform: translateZ(0);

au corps, il a créé un enfant fixe relatif à celui-ci (au lieu de la fenêtre d'affichage). Ainsi, mes éléments fixes left y top sont désormais relatives au conteneur.

J'ai donc fait quelques recherches, et j'ai découvert que la question avait déjà été traitée par Eric Meyer et même si cela ressemblait à un "tour", il s'avère que cela fait partie des spécifications :

Pour les éléments dont la disposition est régie par le modèle de boîte CSS, toute valeur autre qu'aucune pour la transformation entraîne la création à la fois d'un contexte d'empilement et d'un bloc contenant. contexte d'empilement et d'un bloc contenant. L'objet fait office de bloc contenant pour les descendants à position fixe.

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

Ainsi, si vous appliquez une transformation à un élément parent, il deviendra le bloc contenant.

Mais...

Le problème est que l'implémentation semble boguée/créative, parce que les éléments cessent également de se comporter comme fixés (même si cette partie 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 fixe restera toujours fixe).

Une autre chose intéressante (non documentée) est que lorsqu'un élément fixe est contenu à l'intérieur d'un élément transformé, alors que son élément fixe n'a pas été transformé, il n'est pas possible de le transformer. top y left seront désormais liées au conteneur, en respectant les règles de l'UE. box-sizing son contexte de défilement s'étendra au-delà de la bordure de l'élément, comme si la valeur box-sizing était définie sur border-box . Pour certains créatifs, cela pourrait devenir un jouet :)

TEST

10 votes

0 votes

Bien, cela fonctionne pour moi dans Chrome. Une idée sur la façon d'obtenir la même chose dans IE ? J'ai essayé d'utiliser translateZ mais ça n'a marché dans aucune version d'IE.

0 votes

Pareil quelqu'un sait-il comment faire cela dans IE ? C'est un peu pénible de détecter le navigateur, puis de l'afficher ou non de manière systématique. left: (étant donné que ça fout le bordel)

86voto

Shadow_boi Points 924

La réponse est oui, à condition que vous ne mettiez pas en place left: 0 o right: 0 après avoir défini la position de la division comme fixe.

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

Regardez la barre latérale. Elle est fixe, mais liée au parent, et non 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>

16 votes

Une raison pour laquelle il n'y a pas plus de votes positifs ? C'est la solution la plus évidente pour moi.

0 votes

Qu'en est-il de la compatibilité entre navigateurs ? L'un d'entre vous l'a-t-il vérifiée ?

8 votes

C'est correct, mais uniquement pour le "positionnement" de l'élément fixe. Il ne respectera pas la largeur du conteneur et ne sera pas redimensionné de quelque manière que ce soit. Par exemple, si vous avez un wrapper fluide avec max-width:1000px ; margin:auto ; cela ne fonctionnera pas. Si tout peut avoir une largeur fixe, alors oui, cela résoudra votre problème.

20voto

bigspotteddog Points 1080

J'ai créé ce plugin jQuery pour résoudre un problème similaire que j'avais où 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 était déroulée, mais je voulais qu'il soit ancré aux données tabulaires afin qu'il soit là où je place le conteneur (centré, gauche, droite) et qu'il puisse aussi se déplacer de gauche à droite avec la page lorsqu'elle est déroulée horizontalement.

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

https://github.com/bigspotteddog/ScrollToFixed

La description de ce plugin est la suivante :

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

Avec l'option marginTop, l'élément cessera de se déplacer verticalement vers le haut une fois que le défilement vertical aura atteint la position cible ; mais l'élément continuera de se déplacer horizontalement lorsque la page défilera vers la gauche ou la droite. Une fois que le défilement de la page vers le bas a dépassé la position cible, l'élément sera rétabli à sa position initiale 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();
});

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