Flexbox inside list item ne s'aligne pas avec le haut de la liste item
mettre une flexbox à l'intérieur d'un élément de liste fait que le contenu est poussé vers le bas par ce qui semble être une hauteur de ligne complète.
j'ai joué avec différentes propriétés CSS, comme donner la flexbox margin-top: 0
, ses enfants margin-top:0
, en ajoutant flex-wrap
à la flexbox, etc. Pas de dés!
.wrapper {
display: flex;
}
li {
background: #ccc;
}
<ul>
<li>
<div class="wrapper">
<div>hello</div>
<div>world</div>
</div>
</li>
</ul>
3 réponses
cela semble dû à la ::marker
pseudo-élément.
je ne sais pas exactement ce qui doit arriver parce que c'est une superposition de différents specs
- CSS Display 3-The
list-item
mot clé - CSS Pseudo-éléments 4-the
::marker
pseudo-élément - CSS Listes et les Compteurs 3 - Le ::marqueur de pseudo-element
et c'est problématique parce qu'ils sont les propositions ne sont pas prêtes à être mises en œuvre. Voir, par exemple, l'avertissement d' CSS Listes 3 - repères de Positionnement, ce qui est aussi pertinent dans cette question:
cette section n'est pas prête à être mise en oeuvre. C'est un sites en attente brouillon qui n'a même pas été correctement vérifié pour Compatibilité avec le Web. N'hésitez pas à nous envoyer vos commentaires, mais N'utilisez pas cette partie DE LA SPÉCIFICATION.
ce qui suit est mon avis sur la façon dont Chrome traite les marqueurs capuchon.
tout d'abord, utilisons le plus simple list-style-position: inside
sur l'item list, et qu'il contienne un bloc:
ul {
list-style-position: inside;
}
li {
border: 1px solid blue;
}
div {
border: 1px solid red;
}
<ul>
<li>
<div>Hello<br />world</div>
</li>
</ul>
Chrome l'affiche comme ceci:
notez que le marqueur chevauche le div, mais rétrécit sa zone de première ligne. Ce comportement est typique de flotteurs!
un flottant ne doit pas chevaucher une racine de contexte de formatage. Par exemple, display: inline-block
établit un bloc le formatage de contexte.
ul {
list-style-position: inside;
}
li {
border: 1px solid blue;
}
div {
display: inline-block;
border: 1px solid red;
}
<ul>
<li>
<div>Hello<br />world</div>
</li>
</ul>
donc comme un flotteur, le marqueur le pousse vers la droite, pour éviter le chevauchement.
mais notez que le marqueur est aligné verticalement. Et l'établissement d'un contexte de formatage de bloc avec overflow: hidden
n'empêche pas le chevauchement.
ul {
list-style-position: inside;
}
li {
border: 1px solid blue;
}
div {
overflow: hidden;
border: 1px solid red;
}
<ul>
<li>
<div>Hello<br />world</div>
</li>
</ul>
donc il a des comportements de flottement, mais ce n'est pas un flottant.
a mon avis, Chrome continue d'itérer la première boîte dans la liste, puis la première boîte à l'intérieur, et ainsi de suite, jusqu'à ce que la première boîte ne soit plus un bloc. Ensuite, il insère le marqueur juste avant, affiché en ligne-niveau (peut-être inline-block
). Quelque chose comme ceci:
var deepestFirstBlock,
child = listItem;
do {
deepestFirstBlock = child;
child = deepestFirstBlock.firstBoxChild;
} while (child.style.display == 'block');
deepestFirstBlock.insertBefore(marker, deepestFirstBlock.firstBoxChild);
ce n'est pas exactement cela, parce que si le direction
le plus profond premier bloc est de droite à gauche, alors le marqueur est inséré après la dernière case de la première ligne.
par conséquent, comme L'a remarqué Michael_B, lorsque vous écrivez le conteneur intérieur avec display: inline-flex
il n'y a pas d'espace vide. C'est parce que le marqueur est inséré avant lui, et puisque les deux sont au niveau de la ligne, ils apparaissent côte à côte.
ul {
list-style-position: inside;
}
li {
border: 1px solid blue;
}
div {
display: inline-flex;
border: 1px solid red;
}
<ul>
<li>
<div>Hello<br />world</div>
</li>
</ul>
Mais un display: flex
conteneur est au niveau du bloc. Donc, il est contraint d'aller à la ligne suivante. L'espace vide est alors le marqueur, qui occupe la première boîte de ligne.
ul {
list-style-position: inside;
}
li {
border: 1px solid blue;
}
div {
display: flex;
border: 1px solid red;
}
<ul>
<li>
<div>Hello<br />world</div>
</li>
</ul>
cela ne se produit pas avec display: block
, qui est aussi block-level, parce que le marqueur est inséré à l'intérieur. Je suppose que le marqueur n'est pas inséré à l'intérieur d'un conteneur flex au niveau du bloc parce qu'il deviendrait alors un article flex et il pourrait produire une disposition bizarre.
Lorsque vous utilisez l'initiale list-style-position: outside
, il semble que Chrome applique juste une sorte de négatif marge horizontale par rapport au repère, de sorte que la case suivante (qui était la première avant d'insérer le repère) soit alignée à gauche du contenant comme avant d'insérer le repère. Peut-être que le marqueur est aussi flotté, puisque les contenus flottés à l'intérieur de l'élément de liste ne peuvent plus apparaître à sa gauche.
cependant, cette marge négative ne permettra pas au conteneur flex de niveau bloc de monter. C'est pourquoi l'espace reste, même si le marqueur n'est plus y.
notez que ceci contredit le brouillon non révisé non prêt pour la mise en oeuvre, qui dit marqueurs avec list-style-position: outside
devrait position: marker
et
Un élément
position: marker
compte absolument positionné.
les éléments absolument positionnés sont retirés de la circulation et se chevauchent après les éléments, donc le conteneur flexible devrait me déplacer vers le haut.
Firefox semble pour faire quelque chose de simple. list-style-position: inside
, il insère simplement le marqueur comme première boîte (au niveau inline) de l'élément de liste. Il ne tente pas d'itérer des blocs pour insérer le marqueur au niveau le plus profond possible.
Cependant,list-style-position: outside
, il prend sans doute le marqueur hors de flux, tout comme le projet dit. C'est pour ça que tu ne vois pas la place dans Firefox.
Solutions
si vous changez .wrapper
display: flex
inline-flex
, le problème est résolu (démo).
Si vous définissez list-style-type
none
, le problème est résolu (crédit @Ricky_Ruiz dans les commentaires) (démo).
Comportement Du Navigateur
le problème existe dans Chrome, Edge et IE11. Le code original fonctionne très bien à Firefox et Safari.
Explication
je suis actuellement Je ne sais pas ce qui cause le comportement.
Pour une raison quelconque (apparemment le marqueur), la section supérieure de l' li
est hors-limites. Le parent ne permet pas aux enfants d'accéder à la zone.
(mise à jour:Une explication détaillée a été fournie dans le une autre réponse.)
Dans les tests...
- j'ai enlevé
padding
etmargin
ul
et descendance. Il n'a pas aidé. - j'ai joué avec
line-height
etvertical-align
. N'a pas aidé.
en plaçant une hauteur égale à tous les éléments, il est clair que quelque chose force le conteneur flex à rendre plus bas que prévu, et déborder le parent.
ul {
padding: 0;
margin: 0;
height: 100px;
border: 1px solid black;
}
li {
padding: 0;
margin: 0;
background: #ccc;
height: 100%;
}
.wrapper {
display: flex;
padding: 0;
margin: 0;
height: 100%;
border: 1px dashed red;
}
<ul>
<li>
<div class="wrapper">
<div>hello</div>
<div>world</div>
</div>
</li>
</ul>
ajouter display: block
li
Les propriétés style résolvent ceci. Par défaut, les styles d'agent utilisateur définiront li
les éléments à afficher list-item
. les spécifications de la flexbox n'en tiennent pas compte, au lieu de spécifier le comportement pour seulement les éléments block, inline et inline-block (ainsi que les éléments table-cell, qui déclenchent les éléments flex au niveau du block).