web-dev-qa-db-fra.com

Chrome/Safari ne remplit pas 100% de la hauteur du flex

Je veux avoir un menu vertical avec une hauteur spécifique.

Chaque enfant doit remplir la hauteur du parent et avoir un texte aligné au milieu.

Le nombre d'enfants est aléatoire, je dois donc travailler avec des valeurs dynamiques.

Div .container contient un nombre aléatoire d'enfants (.item) qui doivent toujours remplir la hauteur du parent. Pour cela, j'ai utilisé flexbox. 

Pour créer des liens avec du texte aligné au milieu, j’utilise la technique display: table-cell. Mais utiliser des affichages de table nécessite une hauteur de 100%.

Mon problème est que .item-inner { height: 100% } ne fonctionne pas dans Webkit (Chrome). 

  1. Existe-t-il une solution à ce problème? 
  2. Ou existe-t-il une technique différente pour que tous les .item remplissent la hauteur du parent avec un texte aligné verticalement au milieu?

Exemple ici jsFiddle, devrait être vu dans Firefox et Chrome

.container {
  height: 20em;
  display: flex;
  flex-direction: column;
  border: 5px solid black
}
.item {
  flex: 1;
  border-bottom: 1px solid white;
}
.item-inner {
  height: 100%;
  width: 100%;
  display: table;
}
a {
  background: orange;
  display: table-cell;
  vertical-align: middle;
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

164
Ricardo Castañeda

Solution

Utilisez des conteneurs flexibles imbriqués.

Débarrassez-vous des hauteurs en pourcentage. Débarrassez-vous des propriétés de la table. Débarrassez-vous de vertical-align. Évitez le positionnement absolu. Il suffit de rester avec flexbox tout au long.

Appliquez display: flex à l'élément flex (.item), ce qui en fait un conteneur flex. Ceci définit automatiquement align-items: stretch, ce qui indique à l'enfant (.item-inner) d'étendre toute la hauteur du parent.

Important: Supprimez les hauteurs spécifiées des éléments flexibles pour que cette méthode fonctionne. Si un enfant a une hauteur spécifiée (par exemple, height: 100%), il ignorera le align-items: stretch provenant du parent. Pour que la variable stretch fonctionne par défaut, la taille de l'enfant doit être calculée comme suit: auto(explication complète _). 

Essayez ceci (aucun changement en HTML):

.container {
    display: flex;
    flex-direction: column;
    height: 20em;
    border: 5px solid black
}

.item {
    display: flex;                      /* new; nested flex container */
    flex: 1;
    border-bottom: 1px solid white;
}

.item-inner {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */

    /* height: 100%;                    <-- remove; unnecessary */
    /* width: 100%;                     <-- remove; unnecessary */
    /* display: table;                  <-- remove; unnecessary */  
}

a {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */
    align-items: center;                /* new; vertically center text */
    background: orange;

    /* display: table-cell;             <-- remove; unnecessary */
    /* vertical-align: middle;          <-- remove; unnecessary */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

_ { jsFiddle demo } _


Explication

Mon problème est que .item-inner { height: 100% } ne fonctionne pas dans webkit (Chrome).

Cela ne fonctionne pas parce que vous utilisez un pourcentage de hauteur d'une manière non conforme à la mise en œuvre traditionnelle de la spécification.

10.5 Hauteur du contenu: la propriété height

pourcentage
Spécifie une hauteur en pourcentage. Le pourcentage est calculé par rapport à la hauteur de la boîte générée bloc contenant. Si la hauteur du bloc conteneur n'est pas explicitement spécifié et si cet élément n'est pas positionné de manière absolue, la valeur est calculée comme suit: auto.

auto
La hauteur dépend des valeurs des autres propriétés.

En d'autres termes, pour que la hauteur en pourcentage fonctionne sur un enfant entrant, le parent doit avoir une hauteur définie.

Dans votre code, le conteneur de niveau supérieur a une hauteur définie: .container { height: 20em; }

Le conteneur de troisième niveau a une hauteur définie: .item-inner { height: 100%; }

Mais entre eux, le conteneur de second niveau - .item - n'a pas une hauteur définie. Webkit voit cela comme un chaînon manquant.

.item-inner dit à Chrome: donnez-moi height: 100%. Chrome recherche le parent (.item) comme référence et répond: 100% de quoi? Je ne vois rien (en ignorant la règle flex: 1 qui est là). En conséquence, il applique height: auto (hauteur du contenu), conformément à la spéc.

Firefox, en revanche, accepte maintenant la hauteur de flex d'un parent comme référence pour le pourcentage de hauteur de l'enfant. IE11 et Edge acceptent également les hauteurs de flexion.

En outre, Chrome acceptera flex-grow comme référence parent adéquate s'il est utilisé avec flex-basis (toute valeur numérique fonctionne ( auto not), y compris flex-basis: 0). À ce jour, toutefois, cette solution a échoué dans Safari.

#outer {
  display: flex;
  flex-direction: column;
  height: 300px;
  background-color: white;
  border: 1px solid red;
}
#middle {
  flex-grow: 1;
  flex-basis: 1px;
  background-color: yellow;
}
#inner {
  height: 100%;
  background-color: lightgreen;
}
<div id="outer">
  <div id="middle">
    <div id="inner">
      INNER
    </div>
  </div>
</div>


Quatre solutions

1. Spécifiez une hauteur sur tous les éléments parents

Une solution multi-navigateur fiable consiste à spécifier une hauteur pour tous les éléments parents. Cela évite les liens manquants, que les navigateurs Webkit considèrent comme une violation des spécifications.

Notez que min-height et max-height ne sont pas acceptables. Ce doit être la propriété height.

Plus de détails ici: Utilisation de la propriété CSS height et des valeurs en pourcentage }

2. CSS Relative & Absolute Positioning

Appliquez position: relative au parent et position: absolute à l'enfant. 

Dimensionnez l'enfant avec height: 100% et width: 100%, ou utilisez les propriétés de décalage: top: 0, right: 0, bottom: 0, left: 0.

Avec le positionnement absolu, la hauteur en pourcentage fonctionne sans une hauteur spécifiée sur le parent.

3. Supprimez les conteneurs HTML inutiles (recommandé)

Y at-il un besoin de deux conteneurs autour de button? Pourquoi ne pas supprimer .item ou .item-inner, ou les deux? Bien que (button elements) échouent parfois en tant que conteneurs flexibles , ils peuvent être des éléments flexibles. Envisagez de faire de button un enfant de .container ou .item et de supprimer la majoration gratuite.

Voici un exemple:

.container {
    height: 20em;
    display: flex;
    flex-direction: column;
    border: 5px solid black
}

a {
    flex: 1;
    background: orange;
    border-bottom: 1px solid white;
    display: flex;                   /* nested flex container (for aligning text) */
    align-items: center;             /* center text vertically */
    justify-content: center;         /* center text horizontally */
}
<div class="container">
    <a>Button</a>
    <a>Button</a>
    <a>Button</a>
</div>

4. Conteneurs Flex imbriqués (recommandé)

Débarrassez-vous des hauteurs en pourcentage. Débarrassez-vous des propriétés de la table. Débarrassez-vous de vertical-align. Évitez le positionnement absolu. Il suffit de rester avec flexbox tout au long.

Appliquez display: flex à l'élément flex (.item), ce qui en fait un conteneur flex. Ceci définit automatiquement align-items: stretch, ce qui indique à l'enfant (.item-inner) d'étendre toute la hauteur du parent.

Important: Supprimez les hauteurs spécifiées des éléments flexibles pour que cette méthode fonctionne. Si un enfant a une hauteur spécifiée (par exemple, height: 100%), il ignorera le align-items: stretch provenant du parent. Pour que la variable stretch fonctionne par défaut, la taille de l'enfant doit être calculée comme suit: auto(explication complète _). 

Essayez ceci (aucun changement en HTML):

.container {
    display: flex;
    flex-direction: column;
    height: 20em;
    border: 5px solid black
}

.item {
    display: flex;                      /* new; nested flex container */
    flex: 1;
    border-bottom: 1px solid white;
}

.item-inner {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */

    /* height: 100%;                    <-- remove; unnecessary */
    /* width: 100%;                     <-- remove; unnecessary */
    /* display: table;                  <-- remove; unnecessary */  
}

a {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */
    align-items: center;                /* new; vertically center text */
    background: orange;

    /* display: table-cell;             <-- remove; unnecessary */
    /* vertical-align: middle;          <-- remove; unnecessary */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

jsFiddle

297
Michael_B

Solution: supprimez height: 100% dans .item-inner et ajoutez display: flex dans .item

Démo: https://codepen.io/tronghiep92/pen/NvzVoo

4
nghiepit

J'ai eu un problème similaire dans iOS 8, 9 et 10 et les informations ci-dessus ne pouvaient pas résoudre le problème, mais j'ai découvert une solution après une journée de travail sur ce problème. Certes, cela ne fonctionnera pas pour tout le monde, mais dans mon cas, mes éléments étaient empilés dans une colonne et avaient une hauteur de 0 alors que cela aurait dû être la hauteur du contenu. Changer le css pour le ramer et le boucler a résolu le problème. Cela ne fonctionne que si vous avez un seul élément et qu'ils sont empilés, mais comme cela m'a pris une journée pour le découvrir, j'ai pensé que je devrais partager mon correctif!

.wrapper {
    flex-direction: column; // <-- Remove this line
    flex-direction: row; // <-- replace it with
    flex-wrap: wrap; // <-- Add wrapping
}

.item {
    width: 100%;
}
0
Designer023

Pour Mobile Safari, il existe un correctif pour le navigateur. vous devez ajouter -webkit-box pour les appareils iOS.

Ex.

display: flex;
display: -webkit-box;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
align-items: stretch;

si vous utilisez la propriété align-items: stretch; pour l'élément parent, supprimez le height : 100% de l'élément enfant.

0
Narasinghe