web-dev-qa-db-fra.com

Faites en sorte que les éléments flexibles s'étendent sur toute la hauteur et centrent leur contenu verticalement

J'ai une boîte de flexion horizontale (c'est-à-dire flex-direction: row, c'est-à-dire côte à côte) avec quelques éléments. Chaque élément peut être constitué d'une seule ligne de texte ou de plusieurs lignes. Je souhaite aligner verticalement le contenu de chaque élément flexible.

Si chaque élément avait un fond transparent, je pourrais facilement utiliser align-items: center. Cependant, je souhaite que chaque élément soit étiré verticalement, car je souhaite définir un arrière-plan (ou peut-être des bordures, ou peut-être une région cliquable) sur toute la hauteur disponible.

Jusqu'à présent, je sais:

  • Étirement: align-items: stretch
  • Alignement: align-items: center
  • Étirement et alignement: ???

Démo disponible à http://codepen.io/denilsonsa/pen/bVBQQNa

Screenshot of the demo

ul {
  display: flex;
  flex-direction: row;
}
ul.first {
  align-items: stretch;
}
ul.second {
  align-items: center;
}
ul > li {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 5em;
  text-align: center;
}
ul > li:nth-child(2) {
  background: #CFC;
}

/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }
<ul class="first">
  <li>Sample</li>
  <li><span>span</span></li>
  <li><span>multiple</span> <span>span</span></li>
  <li>text <span>span</span></li>
  <li>multi<br>line</li>
</ul>
<hr>
<ul class="second">
  <li>Sample</li>
  <li><span>span</span></li>
  <li><span>multiple</span> <span>span</span></li>
  <li>text <span>span</span></li>
  <li>multi<br>line</li>
</ul>


Questions similaires:

13
Denilson Sá Maia

Malheureusement, il est impossible d'obtenir l'effet souhaité en utilisant le balisage exact affiché dans la question.

La solution implique:

  • Paramétrer display: flex; sur <li>.
  • Envelopper le contenu de <li> dans un autre élément .
    • Ceci est nécessaire car <li> est maintenant un conteneur flex, nous avons donc besoin d'un autre élément pour empêcher le contenu réel de devenir des éléments flex.
    • Dans cette solution, j'ai introduit un élément <div>, mais il aurait pu s'agir d'un autre élément.
  • Maintenant que <li> est un conteneur flex et qu'il ne contient qu'un seul enfant, nous pouvons utiliser align-items et/ou justify-content pour aligner ce nouvel et unique enfant.

L'arbre DOM ressemble à ceci:

<ul> flex-parent, direction=row
 ├ <li> flex-item && flex-parent && background && JavaScript clickable area
 │  └ <div> flex-item as a single transparent element
 │     ├ Actual contents
 │     └ Actual contents
 ├ …

Note: La solution dans cette réponse utilise 2 boîtes flexibles imbriquées. La solution de Michael_B utilise 3 boîtes flexibles imbriquées, car elle présente le défi supplémentaire d’élargir l’élément <a> pour remplir le <li> complet. Lequel est préféré dépend de chaque cas. Si je pouvais, j'accepterais les deux réponses.

/* New code: this is the solution. */
ul > li {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

/* Old code below. */
ul {
  display: flex;
  flex-direction: row;
  align-items: stretch;
}
ul > li {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 5em;
  text-align: center;
}
ul > li:nth-child(2) {
  background: #CFC;
}

/* Visual styles, just ignore. */
html, body { font-family: sans-serif; font-size: 25px; }
ul, li { list-style: none; margin: 0; padding: 0; }
ul { background: #CCF; width: 25em; }

button:focus + ul {
    font-size: 14px;
    width: auto;
}
<button>Click here to set <code>width: auto</code> and reduce the font size.</button>

<!-- New code: there is a single <div> between each <li> and their contents. -->
<ul>
  <li><div>Sample</div></li>
  <li><div><span>span</span></div></li>
  <li><div><span>multiple</span> <span>span</span></div></li>
  <li><div>text <span>span</span></div></li>
  <li><div>multi<br>line</div></li>
</ul>

6
Denilson Sá Maia

Créez les li flex-conteneurs avec flex-direction:column. Je pense que c'est ce que vous recherchez.

html,
body {
  font-family: sans-serif;
  font-size: 25px;
}
ul,
li {
  list-style: none;
  margin: 0;
  padding: 0;
}
ul {
  background: #CCF;
  width: 25em;
  display: flex;
  flex-direction: row;
}
ul.first {
  align-items: stretch;
}
ul > li {
  flex-grow: 1;
  flex-shrink: 0;
  flex-basis: 5em;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  /*outline: 1px dotted #444;*/
}
ul > li:nth-child(2) {
  background: #CFC;
}
<ul class="first">
  <li>Sample</li>
  <li><span>span</span>
  </li>
  <li><span>multiple</span>  <span>span</span>
  </li>
  <li>text <span>span</span>
  </li>
  <li>multi
    <br>line</li>
</ul>

3
Paulie_D

Je veux que chaque élément soit étiré verticalement, parce que je veux définir un arrière-plan (ou peut-être des frontières, ou peut-être que c'est une région cliquable) à toute la hauteur disponible.

Vous pouvez réaliser cette mise en page sans aucune modification de votre structure HTML. Il n'y a pas besoin de conteneurs supplémentaires.

Vous avez déjà un conteneur Flex principal et un groupe d’éléments Flex. Il suffit de transformer ces éléments flexibles en conteneurs flexibles imbriqués. Cela vous permettra d’aligner le contenu avec les propriétés flex.

(Puisque vous avez mentionné que vous pourriez avoir besoin de régions cliquables, je suis passé de li à a elements.)

nav {
  display: flex;
  background: #CCF;
  width: 25em;
}

nav > a {
  flex: auto;  /* flex-grow: 1, flex-shrink: 1, flex-basis: auto */
  text-align: center;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
}
nav > a:nth-child(2) {
  background: #CFC;
}

html, body {
  font-family: sans-serif;
  font-size: 25px;
}
<nav>
  <a href="">Sample</a>
  <a href=""><span>span</span></a>
  <a href=""><span>multiple</span> <span>span</span></a>
  <a href="">text <span>span</span></a>
  <a href="">multi<br>line</a>
</nav>

codepen révisé

Notez que le contenu placé directement dans un conteneur flex est enveloppé dans un élément flex anonyme:

De la spec:

4. Éléments Flex

Chaque enfant entrant d'un conteneur flex devient un élément flex, et chaque série de texte contigu qui est directement contenue dans un fichier flex Le conteneur est emballé dans un article Flex anonyme.

Ainsi, comme le texte est automatiquement enveloppé dans des éléments flexibles, vous pouvez conserver la hauteur totale de chaque élément (align-items: stretch du conteneur principal) et centrer verticalement le contenu (align-items: center des conteneurs imbriqués).

1
Michael_B

Les éléments flex-child peuvent également être des éléments flex-parent.

*,
*:before,
*:after {
  box-sizing: inherit;
}
html {
  box-sizing: border-box;
  font-family: sans-serif;
  font-size: 25px;
}
body {
  display: flex;
  flex-flow: column nowrap;
  background-color: #333;
  overflow: hidden;
}
html,
body {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}

.List {
  padding: 0;
  margin: 0;
  background: #CCF;
  width: 25em;
  list-style: none;
  display: flex;
  flex-flow: row nowrap;
  justify-content: center;
}

.ListItem {
  flex-basis: 5em;
  display: flex;
  flex-flow: row wrap;
  text-align: center;
  align-items: center;
}

.ListItem:nth-child(2) {
  background: #CFC;
}

.ListItem__content {
  width: 100%;
}
<ul class="List">
  <li class="ListItem">
    <span class="ListItem__content">Sample</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">span</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">multiple <br> span</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">span</span>
  </li>
  <li class="ListItem">
    <span class="ListItem__content">multi<br>line</span></li>
</ul>

0
0x860111