"Position: collante;" ne fonctionne pas CSS et HTML


177

Je veux que la barre de navigation reste en haut une fois que je fais défiler dessus, mais cela ne fonctionne pas et je n'ai aucune idée de pourquoi. Si vous pouvez aider, voici mon code HTML et CSS:

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato",sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover{
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav style="position: sticky; position: -webkit-sticky;">
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>


10
position: sticky a besoin d'une coordonnée pour tél où coller
G-Cyrillus

36
Vous devez également faire attention aux éléments parents. position: stickypeut cesser de fonctionner s'il est à l'intérieur d'une flexbox à moins que vous ne soyez prudent et échouera également s'il y a un overflow: hiddenou overflow: autoentre et tout ce qu'il défile à l'intérieur (racine du corps ou ancêtre le plus proche avec débordement: scroll)
user56reinstatemonica8

2
@ user56reinstatemonica8 OMG merci beaucoup de m'avoir parlé du overflow: hiddenet overflow: auto! Je me gratte la tête depuis des jours en essayant de faire fonctionner cette merde
Oneezy

Réponses:


207

Le positionnement collant est un hybride de positionnement relatif et fixe. L'élément est traité comme positionné relative jusqu'à ce qu'il franchisse un seuil spécifié, point auquel il est traité comme positionné fixe.
...
Vous devez spécifier un seuil d'au moins un top, right, bottomou leftpour le positionnement collant à se comporter comme prévu. Sinon, il sera impossible de le distinguer du positionnement relatif. [ source: MDN ]

Donc, dans votre exemple, vous devez définir la position où il doit rester à la fin en utilisant la toppropriété.

html, body {
  height: 200%;
}

nav {
  position: sticky;
  position: -webkit-sticky;
  top: 0; /* required */
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>


124
En général, cette réponse n'est pas suffisante pour coller au travail, le parent ne doit pas non plus avoir de propriété de débordement.
ViliusL

Merci pour votre commentaire. Je suis d'accord avec vous que pour d'autres exemples que les PO, ma réponse pourrait ne pas être suffisante. Les autres réponses le soulignent :)
Marvin

Je pense que l'astuce est que la position sticky ne peut être appliquée qu'aux enfants qui appartiennent à un parent scrollable avec une hauteur connue, (un enfant direct dans une flexbox a une hauteur connue qui est calculée à partir d'un autre flex-item)
code4j

@ViliusL merci pour ton commentaire! C'était le problème que j'avais avec la position: collant, je ne l'aurais pas su sans vous car je n'ai trouvé cette information nulle part.
Piotr Szlagura le

la position persistante ne devrait pas avoir un parent avec la propriété de débordement, également sticky n'est pas pris en charge dans certains navigateurs Web
Rohan Shenoy

331

Vérifiez si un élément ancêtre a un jeu de débordement (par exemple overflow:hidden); essayez de le basculer. Vous devrez peut-être remonter l'arborescence DOM plus haut que prévu =).

Cela peut affecter votre position:stickysur un élément descendant.


36
J'aimerais pouvoir vous voter plusieurs fois! Cela m'a mordu plus souvent que je ne voudrais l'admettre.
Alexander Varwijk

2
C'est la bonne réponse. Cependant, il peut être difficile de trouver quel élément parent est à l'origine du problème. J'ai écrit un script jquery pour aider à identifier la propriété de débordement sur les parents qui ont identifié le problème (exécutez-le simplement dans votre console). Parce que le script est composé de quelques lignes, j'ai ajouté une réponse contenant le script ci-dessous.
danday74

5
J'ai manqué le "s" dans vos "éléments parents"
che-azeh

5
J'ai également manqué le "s" :( et c'était le problème. Dans de nombreux endroits, les gens écrivent que vous ne devriez vérifier que les parents, pas tous les parents. J'ai trouvé mon problème en vérifiant si un appel $(stickyElement).parents().css("overflow", "visible")dans la console Web pouvait aider et c'est le cas. Ensuite, j'ai localisé le parent éloigné avec le overflow:hiddenstyle qui a causé le problème. J'aimerais lire cette réponse plus attentivement.
Mariusz Pawelski

2
Si vous avez besoin de vérifier overflow:hidden, vous pouvez exécuter ce script dans la console de votre navigateur pour vérifier tous les parents / ancêtres d'un élément donné: gist.github.com/brandonjp/478cf6e32d90ab9cb2cd8cbb0799c7a7
brandonjp

100

J'ai le même problème et j'ai trouvé la réponse ici .

Si votre élément ne colle pas comme prévu, la première chose à vérifier sont les règles appliquées au conteneur.

Plus précisément, recherchez toute propriété de débordement définie sur le parent. Vous ne pouvez pas utiliser : overflow: hidden, overflow: scrollou overflow: autosur le parent d'un position: stickyélément.


C'est aussi la bonne réponse mais voyez aussi ma réponse qui permet d'identifier facilement le parent à l'origine du problème.
danday74

10
Vous devriez vérifier non seulement conteneur parent le plus proche , mais tous les éléments de parent s .
Mariusz Pawelski

oui, voyez ma réponse pour faire exactement cela et vérifiez TOUS les parents très rapidement
danday74

1
Le lien m'a aidé aussi. Mon problème a été résolu par "... Si vous n'utilisez pas de débordement et que vous rencontrez toujours des problèmes, il vaut la peine de vérifier si une hauteur est définie sur le parent ..."
xenetics

Économiseur de vie, description très simple du problème, mais y a-t-il un moyen de contourner ce problème?
Rahul Singh

32

Peu de choses que j'ai rencontrées:

Lorsque votre élément collant est un composant (angulaire, etc.)

  • Si l'élément `` collant '' lui-même est un composant avec un sélecteur d'élément personnalisé, tel qu'un composant angulaire nommé, <app-menu-bar>vous devrez ajouter ce qui suit au css du composant:

    :host { display: block; }   

    ou

    app-menu-bar  { display: block; }   // (in the containing component's css)

    Safari sur iOS en particulier semble exiger display:blockmême sur l'élément racine app-rootd'une application angulaire ou il ne collera pas.

  • Si vous créez un composant et définissez le css à l'intérieur du composant (shadow DOM / styles encapsulés), assurez-vous que le position: stickyest appliqué au sélecteur `` externe '' (par exemple, app-menu-bardans devtools devrait afficher la position collante) et non un niveau supérieur div dans le composant. Avec Angular, cela peut être réalisé avec le :hostsélecteur dans le css pour votre composant.

    :host
    {
        position: sticky;
        display: block;   // this is the same as shown above
        top: 0;
        background: red;    
    }

Autre

  • Si l'élément suivant votre élément collant a un arrière-plan uni, vous devez ajouter ce qui suit pour l'empêcher de glisser en dessous:

    .sticky-element { z-index: 100; }
    .parent-of-sticky-element { position: relative; }
  • Votre élément collant doit être le premier (avant votre contenu) s'il est utilisé topet après celui-ci s'il est utilisé bottom.

  • Il y a des complications lors de l'utilisation overflow: hiddensur votre élément wrapper - en général, cela tuera l'élément collant à l'intérieur. Mieux expliqué dans cette question

  • Les navigateurs mobiles peuvent désactiver les éléments à position fixe / fixe lorsque le clavier à l'écran est visible. Je ne suis pas sûr des règles exactes (personne ne le sait jamais) mais lorsque le clavier est visible, vous regardez une sorte de `` fenêtre '' dans la fenêtre et vous ne pourrez pas facilement faire coller les choses haut visible réel de l'écran.

  • Assurez-vous que vous avez:

    position: sticky;

    et pas

    display: sticky;

Divers problèmes d'utilisabilité

  • Soyez prudent si votre conception nécessite de coller des éléments au bas de l'écran sur les appareils mobiles. Sur l'iPhone X, par exemple, ils affichent une ligne étroite pour indiquer la zone de balayage (pour revenir à la page d'accueil) - et les éléments à l'intérieur de cette région ne sont pas cliquables. Donc, si vous collez quelque chose, assurez-vous de tester sur l'iPhone X que les utilisateurs peuvent l'activer. Un gros bouton «Acheter maintenant» ne sert à rien si les gens ne peuvent pas cliquer dessus!
  • Si vous faites de la publicité sur Facebook, la page Web est affichée dans un contrôle «Webview» dans les applications mobiles de Facebook. Surtout lors de l'affichage de la vidéo (où votre contenu commence dans la moitié inférieure de l'écran uniquement) - ils gâchent souvent complètement les éléments collants en plaçant votre page dans une fenêtre déroulante qui permet en fait à vos éléments collants de disparaître du haut de la page. Assurez-vous de tester dans le contexte d'une annonce réelle et pas seulement dans le navigateur du téléphone ou même le navigateur de Facebook qui peuvent tous se comporter différemment.

@Sergey Je ne suis pas tout à fait sûr de savoir lequel display: blocket qui position: relativedéclenche le comportement correct dans Safari - semblait-il que seul display: blockétait nécessaire? Bien sûr, cela ne fait probablement pas de mal d'avoir les deux spécifiés
Simon_Weaver

2
display: blockC'était juste assez
Sergey

27

Ceci est une continuation des réponses de MarsAndBack et Miftah Mizwar.

Leurs réponses sont correctes. Cependant, il est difficile d'identifier le ou les ancêtres du problème.

Pour rendre cela très simple, exécutez simplement ce script jQuery dans la console de votre navigateur et il vous indiquera la valeur de la propriété overflow sur chaque ancêtre.

$('.your-sticky-element').parents().filter(function() {
    console.log($(this));
    console.log($(this).css('overflow'));
    return $(this).css('overflow') === 'hidden';
});

Là où un ancêtre n'a pas overflow: visiblechangé son CSS pour qu'il le fasse!

De plus, comme indiqué ailleurs, assurez-vous que votre élément collant a ceci dans le CSS:

.your-sticky-element {
    position: sticky;
    top: 0;
}

2
Cela a été très utile. J'ai pu identifier rapidement l'élément parent qui avait une valeur de overflow: invisible.
David Brower

4
Si vous n'avez pas jQuery sur votre page, vous pouvez exécuter ce petit extrait de code dans la console pour l'ajouter: (async function() { let response = await fetch('https://code.jquery.com/jquery-3.3.1.min.js'); let script = await response.text(); eval(script); })();
magikMaker

8
Vous pouvez également exécuter cet extrait de code qui ne nécessite pas que JQuery trouve un parent de débordement non "visible": var p = $0.parentElement; while(p != null) { var ov = getComputedStyle(p).overflow; if(ov !== 'visible') console.warn(ov, p); else console.log(ov, p); p = p.parentElement; }$0est le dernier élément sélectionné dans les outils de développement.
Mariusz Pawelski

On pourrait aussi bien gérer position: fixedet s'approprier les propriétés avec JavaScript. La question n'indique pas le besoin de JavaScript.
vintproykt il y a

12

J'ai dû utiliser le CSS suivant pour le faire fonctionner:

.parent {
    display: flex;
    justify-content: space-around;
    align-items: flex-start;
    overflow: visible;
}

.sticky {
    position: sticky;
    position: -webkit-sticky;
    top: 0;
}

Si ci-dessus ne fonctionne pas, alors ...

Passez en revue tous les ancêtres et assurez-vous qu'aucun de ces éléments ne l'a fait overflow: hidden. Vous devez changer cela enoverflow: visible


1
affichage: flex fait la chose
MaciejLisCK

6

Si vous êtes tombé sur ceci et que votre sticky ne fonctionne pas - essayez de configurer le parent sur:

display: unset

A travaillé pour moi


C'est la bonne.
mm-93 le

Oh! Cela semble être une solution pour le cas où un élément parent a une hauteur limitée (par exemple un conteneur de barre de navigation ou quelque chose, par opposition à un corps entier ou à un conteneur de page) - il semble que les stickies n'aiment pas faire défiler en dehors de leur parents (ce qui est tout à fait ridicule!) Maintenant, tout le monde a juste besoin d'avoir la chance de pouvoir confier le parent display: unset, ce qui n'est peut-être pas toujours immédiatement viable
Ben Philipp

Semble également travailler avec contents, initial(?) Etinline
Ben Philipp

5

Moment drôle qui n'était pas évident pour moi: au moins dans Chrome 70 position: stickyn'est pas appliqué si vous l'avez défini en utilisant DevTools.


Avez-vous une source pour cela ou toute autre information sur la façon de contourner ce problème?
AJMansfield

5

Il semble que la barre de navigation à coller ne devrait pas être à l'intérieur d'une div ou d'une section avec un autre contenu. Aucune des solutions ne fonctionnait pour moi jusqu'à ce que j'aie retiré la barre de navigation du div que la barre de navigation partageait avec une autre barre supérieure. J'avais auparavant la barre supérieure et la barre de navigation enveloppées avec un div commun.


Merci, c'est ce que je cherchais! Pour moi, il n'y avait pas de parents avec un débordement, ni de problèmes de hauteur. Ce serait bien de voir également cette information dans la réponse acceptée.
saglamcem

Je viens de découvrir en expérimentant que le sticky ne défilera pas en dehors de son élément parent. Peu importe le nombre d'autres frères et sœurs qu'il a, mais son parent ne peut apparemment pas être un conteneur de barre de navigation, mais doit être quelque chose au niveau d'une page / conteneur de contenu: (C'est ridicule
Ben Philipp

Mais Lo! Si vous le pouvez, si vous définissez le parent limitant sur display: unset, cette restriction est levée! voir stackoverflow.com/a/60560997/2902367 Semble également fonctionner avec contents, initial(?) etinline
Ben Philipp

4

de mon commentaire:

position:sticky a besoin d'un coordoné pour savoir où coller

nav {
  position: sticky;
  top: 0;
}

.nav-selections {
  text-transform: uppercase;
  letter-spacing: 5px;
  font: 18px "lato", sans-serif;
  display: inline-block;
  text-decoration: none;
  color: white;
  padding: 18px;
  float: right;
  margin-left: 50px;
  transition: 1.5s;
}

.nav-selections:hover {
  transition: 1.5s;
  color: black;
}

ul {
  background-color: #B79b58;
  overflow: auto;
}

li {
  list-style-type: none;
}

body {
  height: 200vh;
}
<nav>
  <ul align="left">
    <li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
    <li><a href="#/about" class="nav-selections">About</a></li>
    <li><a href="#/products" class="nav-selections">Products</a></li>
    <li><a href="#" class="nav-selections">Home</a></li>
  </ul>
</nav>

Il existe un polyfill à utiliser pour d'autres navigateurs que FF et Chrome. Il s'agit d'une règle expérimentale qui peut être implémentée ou non à tout moment via les navigateurs. Chrome l'a ajouté il y a quelques années, puis l'a laissé tomber, il semble que ça revienne ... mais pour combien de temps?

Le plus proche serait position: relative + coordonnées mises à jour lors du défilement une fois atteint le point collant, si vous voulez transformer cela en un script javascript


4

Je sais que cela semble avoir déjà été répondu, mais je suis tombé sur un cas spécifique et je pense que la plupart des réponses passent à côté de l'essentiel.

Les overflow:hiddenréponses couvrent 90% des cas. C'est plus ou moins le scénario "sticky nav".

Mais le comportement collant est mieux utilisé dans la hauteur d'un conteneur. Pensez à un formulaire de newsletter dans la colonne de droite de votre site Web qui défile vers le bas avec la page. Si votre élément collant est le seul enfant du conteneur, le conteneur a exactement la même taille et il n'y a pas de place pour faire défiler.

Votre conteneur doit être à la hauteur dans laquelle vous vous attendez à ce que votre élément défile. Ce qui dans mon scénario "colonne de droite" est la hauteur de la colonne de gauche. La meilleure façon d'y parvenir est d'utiliser display:table-cellsur les colonnes. Si vous ne pouvez pas, et que vous êtes coincé avec float:rightet comme moi, vous devrez soit deviner la hauteur de la colonne de gauche, soit la calculer avec Javascript.


2
"Si votre élément collant est le seul enfant du conteneur, le conteneur a exactement la même taille et il n'y a pas de place pour faire défiler." OR!!! Je vous remercie!
Mark Jackson

Oui! Il m'a fallu un certain temps pour comprendre celui-ci. J'ai trouvé cela ridicule au début, mais je suppose qu'il devrait y avoir au moins une option pour cela. Je préférerais de loin quelque chose comme sticky-limit: parent, sticky-limit: bodyou sticky-limit: nth-parent(3)... Quoi qu'il en soit: si vous le pouvez, vous pouvez lever cette limitation en définissant le parent limitant sur display: unset, comme indiqué dans stackoverflow.com/a/60560997/2902367 . Semble également travailler avec contents, initial(?) Etinline
Ben Philipp

3

Je sais que c'est un ancien message. Mais s'il y a quelqu'un comme moi qui a récemment commencé à jouer avec la position: collant cela peut être utile.

Dans mon cas, j'utilisais position: sticky comme élément de grille. Cela ne fonctionnait pas et le problème était un overflow-x: hidden sur l' htmlélément. Dès que j'ai supprimé cette propriété, cela a bien fonctionné. Avoir overflow-x: hidden sur l' bodyélément semblait fonctionner bien, je ne sais pas pourquoi encore.


1

deux réponses ici:

  1. supprimer la overflowpropriété de la bodybalise

  2. réglé height: 100%sur bodypour résoudre le problème avecoverflow-y: auto

min-height: 100% ne fonctionne pas au lieu de height: 100%


1

Je pense que cet article en dit long sur le stickyfonctionnement

Comment fonctionne vraiment CSS Position Sticky! La position CSS collante comporte deux parties principales, un élément collant et un conteneur collant .

Article collant  - est l'élément que nous avons défini avec la position: styles collants. L'élément flotte lorsque la position de la fenêtre correspond à la définition de position, par exemple:top: 0px .

Sticky Container - est l'élément HTML qui encapsule l'élément permanent.Il s'agit de la zone maximale dans laquelle l'élément collant peut flotter.

Lorsque vous définissez un élément avec position: sticky, vous définissez automatiquement l'élément parent comme un conteneur collant!


1

Le comportement réel d'un élément collant est:

  • D'abord c'est relatif pendant un moment
  • puis il est fixé pendant un certain temps
  • enfin, il disparaît de la vue

Un élément positionné de manière collante est traité comme étant relativement positionné jusqu'à ce que son bloc contenant franchisse un seuil spécifié (tel que définir top sur une valeur autre que auto) dans sa racine de flux (ou le conteneur dans lequel il défile), auquel point il est traité comme "bloqué "jusqu'à rencontrer le bord opposé de son bloc contenant.

L'élément est positionné selon le flux normal du document, puis décalé par rapport à son ancêtre défilant le plus proche et contenant le bloc (ancêtre au niveau du bloc le plus proche), y compris les éléments liés à la table, en fonction des valeurs de haut, droit, bas, et gauche. Le décalage n'affecte pas la position des autres éléments.

Cette valeur crée toujours un nouveau contexte d'empilement. Notez qu'un élément collant "colle" à son ancêtre le plus proche qui a un "mécanisme de défilement" (créé lorsque le débordement est caché, défilement, automatique ou superposition), même si cet ancêtre n'est pas l'ancêtre de défilement le plus proche.

Cet exemple vous aidera à comprendre:

code https://codepen.io/darylljann/pen/PpjwPM


0

si le correctif de danday74 ne fonctionne pas, vérifiez que l'élément parent a une hauteur.

Dans mon cas, j'avais deux enfants, un flottant à gauche et un flottant à droite. Je voulais que le bon flottant devienne collant mais j'ai dû ajouter un <div style="clear: both;"></div>à la fin du parent, pour lui donner de la hauteur.


Je ne sais float:leftpas pourquoi cela a été critiqué par quelqu'un, mais c'était exactement mon cas: j'ai ajouté à l'élément parent (sans flotteur, sa hauteur était de 0) et j'ai position:stickytravaillé.
aexl

0

J'ai utilisé une solution JS. Cela fonctionne dans Firefox et Chrome. Tout problème, faites le moi savoir.

html

<body>
  <header id="header">
    <h1>Extra-Long Page Heading That Wraps</h1>
    <nav id="nav">
      <ul>
        <li><a href="" title="">Home</a></li>
        <li><a href="" title="">Page 2</a></li>
        <li><a href="" title="">Page 3</a></li>
      </ul>
    </nav>
  </header>
  <main>
    <p><!-- ridiculously long content --></p>
  </main>
  <footer>
    <p>FOOTER CONTENT</p>
  </footer>
  <script src="navbar.js" type="text/javascript"></script>
</body>

css

nav a {
    background: #aaa;
    font-size: 1.2rem;
    text-decoration: none;
    padding: 10px;
}

nav a:hover {
    background: #bbb;
}

nav li {
    background: #aaa;
    padding: 10px 0;

}

nav ul  {
    background: #aaa;
    list-style-type: none;
    margin: 0;
    padding: 0;

}

@media (min-width: 768px) {

    nav ul {
        display: flex;
    }
}

js

function applyNavbarSticky() {
    let header = document.querySelector('body > header:first-child')
    let navbar = document.querySelector('nav')
    header.style.position = 'sticky'

    function setTop() {
        let headerHeight = header.clientHeight
        let navbarHeight = navbar.clientHeight
        let styleTop = navbarHeight - headerHeight

        header.style.top = `${styleTop}px`
    }

    setTop()

    window.onresize = function () {
        setTop()
    }
}

0

z-indexest également très important. Parfois, cela fonctionnera mais vous ne le verrez tout simplement pas. Essayez de le régler sur un nombre très élevé pour être sûr. Aussi, ne mettez pas toujours top: 0mais essayez quelque chose de plus haut au cas où il serait caché quelque part (sous une barre d'outils).


0

Voici ce qui m'a fait trébucher ... ma div rémanente était à l'intérieur d'une autre div afin que la div parent ait besoin de contenu supplémentaire APRÈS la div rémanente, pour rendre la div parent "suffisamment grande" pour que la div rémanente "glisse" sur d'autres contenus comme vous faites défiler vers le bas.

Donc, dans mon cas, juste après le sticky div, j'ai dû ajouter:

    %div{style:"height:600px;"} 
      &nbsp;

(Mon application comporte deux divs côte à côte, avec une image "haute" à gauche et un court formulaire de saisie de données à droite, et je voulais que le formulaire de saisie de données flotte à côté de l'image lorsque vous faites défiler vers le bas, donc le formulaire est toujours à l'écran. Cela ne fonctionnerait pas tant que j'aurais ajouté le "contenu supplémentaire" ci-dessus pour que le div collant ait quelque chose à "glisser"


-1

Il est VRAI que le overflowdoit être supprimé ou défini sur initialpour que les position: stickytravaux sur l'élément enfant soient exécutés . J'ai utilisé Material Design dans mon application Angular et j'ai découvert que certains composants Material changeaient la overflowvaleur. Le correctif pour mon scénario est

mat-sidenav-container, mat-sidenav-content {
  overflow: initial;
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.