C'est une question lorsque j'ai lu un article sur le MDN position
propriété . Je pensais qu'il y avait une différence claire entre le comportement de sticky
décrit là-bas et le comportement réel.
Selon le MDN, des éléments de position fixes sont traités comme des éléments de position relative jusqu'à ce que le seuil spécifié soit dépassé, et lorsque le seuil est dépassé, ils sont traités comme des éléments de position fixe jusqu'à ce que la limite de l'élément parent soit atteinte ( link) ).
Le positionnement collant peut être considéré comme un hybride de positionnement relatif et fixe. Un élément positionné collectif est traité comme relativement positionné jusqu'à ce qu'il traverse un seuil spécifié, à quel point il est traité comme fixé jusqu'à ce qu'il atteigne la limite de son parent. Par exemple...
#one { position: sticky; top: 10px; }
... positionnez-vous l'élément avec ID un relativement jusqu'à ce que la fenêtre soit défilée de sorte que l'élément soit inférieur à 10 pixels du haut. Au-delà de ce seuil, l'élément serait fixé à 10 pixels du haut.
Donc, j'ai créé le code suivant et j'ai confirmé l'opération.
body {
margin: 0;
}
.container {
display: flex;
flex-direction: column;
}
.container>* {
width: 100%;
}
header {
background: #ffa;
height: 130vh;
}
main {
background: #faf;
height: 210vh;
}
footer {
background: #faa;
height: 8vh;
position: sticky;
bottom: 0;
}
.footer {
background: #aff;
height: 100vh;
}
<div class="container">
<header>HEADER</header>
<main>MAIN CONTENT</main>
<footer>FOOTER</footer>
<div class="footer"></div>
</div>
Selon le article MDN , ce code "est un élément de placement relatif jusqu'à la position de l'élément inférieur à 0px du bas de la fenêtre en faisant défiler la fenêtre de la fenêtre et devient un élément de placement fixe lorsqu'il est plus de 0px du bas "Je pensais.
Cependant, le résultat est l'action de "Faites défiler jusqu'à l'élément de position fixe jusqu'à ce que la position de l'élément devienne inférieure à 0px de l'extrémité inférieure de la fenêtre de vue en faisant défiler la fenêtre de fenêtre et deviennent l'élément arrangé relatif de plus de 0px de la valeur inférieure. finir".
Pourquoi spécifie le bottom:0
résultat dans l'opposé du comportement indiqué dans le MDN?
Lorsque top: 0
est spécifié, la position relative est appliquée lorsque l'élément n'atteint pas bottom: 0
de la fenêtre de la fenêtre et quand il atteint, une position fixe est appliquée. Lorsque bottom: 0
est spécifié, l'inverse est vrai. La position relative est appliquée lorsque l'élément n'atteint pas le bottom: 0
de la fenêtre de la fenêtre, la position fixe est appliquée lorsqu'elle est atteinte
J'ai lu CSS mais son mécanisme était difficile à lire
Selon le MDN, les éléments de position fixes sont traités comme des éléments de position relative jusqu'à ce que le seuil spécifié soit dépassé.
C'est tout une question de langue ici car la phrase ci-dessus ne signifie pas que l'élément sera nécessaire de commencer position:relative
alors devenir corrigé. Il dit jusqu'à Le seuil spécifié est dépassé. Donc, si autrement, nous avons le seuil spécifié dépassé? C'est en fait le cas de votre exemple.
En d'autres termes, position:sticky
a deux états.
Lequel sera le premier dépendra de votre structure HTML.
Voici un exemple de base pour illustrer:
body {
height:150vh;
margin:0;
display:flex;
flex-direction:column;
border:2px solid;
margin:50px;
}
.b {
margin-top:auto;
position:sticky;
bottom:0;
}
.a {
position:sticky;
top:0;
}
<div class="a">
I will start relative then I will be fixed
</div>
<div class="b">
I will start fixed then I will be relative
</div>
Vous pouvez également avoir un mélange. Nous commençons à résoudre, deviennent relatifs, puis fixé à nouveau:
body {
height:250vh;
margin:0;
display:flex;
flex-direction:column;
border:2px solid;
margin:50px;
}
body:before,
body:after {
content:"";
flex:1;
}
.a {
position:sticky;
top:0;
bottom:0;
}
<div class="a">
I will start fixed then relative then fixed
</div>
Comme vous pouvez le constater dans les exemples ci-dessus, les deux états sont indépendants. Si l'état du position:fixed
est vrai alors nous avons position:fixed
, sinon, il est relatif.
Nous pouvons considérer que le navigateur implémentera ce pseudo code:
on_scroll_event() {
if(threshold exceeded)
position <- fixed
else
position <- relative
}
Pour une compréhension plus précise et complète du mécanisme, vous devez envisager 3 éléments. L'élément collant (et les valeurs de haut/bas/inférieur/gauche/droite), le bloc contenant de l'élément collant et l'ancêtre le plus proche avec une boîte de défilement.
Gauche/haut/haut/bas/droite sont calculés relativement à la boîte de défilement et le bloc contenant définira la limite de l'élément collant.
Voici un exemple pour illustrer:
body {
margin:0;
}
.wrapper {
width:300px;
height:150px;
border:2px solid red;
overflow:auto;
}
.parent {
height:200%;
margin:100% 0;
border:2px solid;
}
.sticky {
position:sticky;
display:inline-block;
margin:auto;
top:20px;
background:red;
}
.non-sticky {
display:inline-block;
background:blue;
}
<div class="wrapper"><!-- our scrolling box -->
<div class="parent"><!-- containing block -->
<div class="sticky">I am sticky</div>
<div class="non-sticky">I am the relative position</div>
</div>
</div>
Initialement, notre élément est caché qui est logique car il ne peut pas être en dehors de son bloc contenant (sa limite). Une fois que nous avons commencé à faire défiler, nous verrons nos éléments collants et relatifs qui se comportent exactement les mêmes. Quand nous avons une distance de 20px
entre l'élément collant et le bord supérieur de la boîte de défilement que nous atteignons le seuil et nous commençons à avoir position:fixed
jusqu'à ce que nous atteignions à nouveau la limite du bloc contenant en bas (c'est-à-dire que nous n'avons plus de place pour le comportement collant)
Maintenant, remplacons le haut avec le bas
body {
margin:0;
}
.wrapper {
width:300px;
height:150px;
border:2px solid red;
overflow:auto;
}
.parent {
height:200%;
margin:100% 0;
border:2px solid;
}
.sticky {
position:sticky;
display:inline-block;
margin:auto;
bottom:20px;
background:red;
}
.non-sticky {
display:inline-block;
background:blue;
}
<div class="wrapper"><!-- our scrolling box -->
<div class="parent"><!-- containing block -->
<div class="sticky">I am sticky</div>
<div class="non-sticky">I am the relative position</div>
</div>
</div>
Rien ne se passera parce que quand il y a une distance de 20px
Entre l'élément et le bord inférieur de la boîte de défilement L'élément collant touche déjà le bord supérieur du bloc contenant et ne peut pas aller à l'extérieur.
Ajoutons un élément avant:
body {
margin:0;
}
.wrapper {
width:300px;
height:150px;
border:2px solid red;
overflow:auto;
}
.parent {
height:200%;
margin:100% 0;
border:2px solid;
}
.sticky {
position:sticky;
display:inline-block;
margin:auto;
bottom:20px;
background:red;
}
.non-sticky {
display:inline-block;
background:blue;
}
.elem {
height:50px;
width:100%;
background:green;
}
<div class="wrapper"><!-- our scrolling box -->
<div class="parent"><!-- containing block -->
<div class="elem">elemen before</div>
<div class="sticky">I am sticky</div>
<div class="non-sticky">I am the relative position</div>
</div>
</div>
Maintenant nous avons créé 50px
d'espace pour avoir un comportement collant. Ajoutons de haut en bas avec le bas:
body {
margin:0;
}
.wrapper {
width:300px;
height:150px;
border:2px solid red;
overflow:auto;
}
.parent {
height:200%;
margin:100% 0;
border:2px solid;
}
.sticky {
position:sticky;
display:inline-block;
margin:auto;
bottom:20px;
top:20px;
background:red;
}
.non-sticky {
display:inline-block;
background:blue;
}
.elem {
height:50px;
width:100%;
background:green;
}
<div class="wrapper"><!-- our scrolling box -->
<div class="parent"><!-- containing block -->
<div class="elem">elemen before</div>
<div class="sticky">I am sticky</div>
<div class="non-sticky">I am the relative position</div>
</div>
</div>
Nous avons maintenant les deux comportements de haut et de bas et la logique peut être reprise comme suit:
on_scroll_event() {
if( top_sticky!=auto && distance_top_sticky_top_scrolling_box <20px && distance_bottom_sticky_bottom_containing_block >0) {
position <- fixed
} else if(bottom_sticky!=auto && distance_bottom_sticky_bottom_scrolling_box <20px && distance_top_sticky_top_containing_block >0) {
position <- fixed
} else (same for left) {
position <- fixed
} else (same for right) {
position <- fixed
} else {
position <- relative
}
}
Les spécifications sont difficiles à comprendre alors voici ma tentative de les expliquer en fonction de MDN . Quelques définitions d'abord:
position: sticky
Un élément collant ayant position: sticky; top: 100px;
est positionné comme suit:
L'exemple suivant montre comment ces règles fonctionnent:
body { font: medium sans-serif; text-align: center; }
body::after { content: ""; position: fixed; top: 100px; left: 0; right: 0; border: 1px solid #F00; }
header, footer { height: 75vh; background-color: #EEE; }
.containing-block { border-bottom: 2px solid #FA0; background: #DEF; }
.containing-block::after { content: ""; display: block; height: 100vh; }
.before-sticky { border-bottom: 2px solid #080; padding-top: 50px; }
.after-sticky { border-top: 2px solid #080; padding-bottom: 50px; }
.sticky { position: sticky; top: 100px; padding-top: 20px; padding-bottom: 20px; background-color: #CCC; }
<header>header</header>
<div class="containing-block">
<div class="before-sticky">content before sticky</div>
<div class="sticky">top sticky</div>
<div class="after-sticky">content after sticky</div>
</div>
<footer>footer</footer>
De même, un élément collant ayant position: sticky; bottom: 100px;
est positionné comme suit:
body { font: medium sans-serif; text-align: center; }
body::after { content: ""; position: fixed; bottom: 100px; left: 0; right: 0; border: 1px solid #F00; }
header, footer { height: 75vh; background-color: #EEE; }
.containing-block { border-top: 2px solid #FA0; background: #DEF; }
.containing-block::before { content: ""; display: block; height: 100vh; }
.before-sticky { border-bottom: 2px solid #080; padding-top: 50px; }
.after-sticky { border-top: 2px solid #080; padding-bottom: 50px; }
.sticky { position: sticky; bottom: 100px; padding-top: 20px; padding-bottom: 20px; background-color: #CCC; }
<header>header</header>
<div class="containing-block">
<div class="before-sticky">content before sticky</div>
<div class="sticky">bottom sticky</div>
<div class="after-sticky">content after sticky</div>
</div>
<footer>footer</footer>
J'espère que c'est une explication assez simple.