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>

codepen

18
demandé sur Michael_B 2016-11-04 02:37:27

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

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:

enter image description here

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>

enter image description here

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>

enter image description here

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>

enter image description here

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.

12
répondu Oriol 2016-11-07 01:28:48

Solutions

si vous changez .wrapperdisplay: flexinline-flex, le problème est résolu (démo).

Si vous définissez list-style-typenone, 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 et marginul et descendance. Il n'a pas aidé.
  • j'ai joué avec line-height et vertical-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>

codepen révisé

7
répondu Michael_B 2017-05-23 11:46:34

ajouter display: blockli 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).

1
répondu coreyward 2016-11-03 23:52:12