web-dev-qa-db-fra.com

Base Flex 100% dans la colonne flexbox: pleine hauteur dans Firefox, pas dans Chrome

Je voudrais une colonne de divs, de n'importe quel nombre, chacune avec une largeur de 100% et une hauteur de 100% de leur div parent, donc l'une est visible initialement, et les autres débordent le parent vers le bas. J'ai configuré les divs pour avoir flex: 0 0 100%;, à l'intérieur d'un div parent avec display: flex et flex-direction: column pour y parvenir.

Le div parent est lui-même de hauteur inconnue, il est donc aussi un enfant d'un display: flex et flex-direction: column, mis à flex: 1 0 0 pour prendre l'espace restant dans son conteneur.

Dans Firefox, la sortie est comme je le voudrais:

Firefox nested flex boxes

Cependant, pas dans Chrome:

Chrome nested flex boxes

Comment puis-je obtenir le style Firefox dans Chrome, sans Javascript?

Vous pouvez le voir en action sur http://plnkr.co/edit/WnAcmwAPnFaAhqqtwhLL?p=preview , ainsi que la version correspondante avec flex-direction: row, qui fonctionne de manière cohérente dans Firefox et Chrome.

Pour référence, le CSS complet

.wrapper {
  display: flex;
  flex-direction: column;
  height: 150px;
  width: 200px;
  border: 4px solid green;
  margin-bottom: 20px;
}

.column-parent {
  flex: 1 0 0;
  display: flex;
  flex-direction: column;
  border: 2px solid blue;
}

.column-child {
  flex: 0 0 100%;
  border: 2px solid red;
}

et HTML

<div class="wrapper">
  <p>Some content of unknown size</p>
  <div class="column-parent">
    <div class="column-child">
      Should be inside green
    </div>
    <div class="column-child">
      Should be outside green
    </div>
  </div>
</div>
36
Michal Charemza

Comme indiqué dans la réponse d'Abhitalks, il y a un bogue (ou une interprétation différente de la norme) dans la manière Chrome gère l'attribut height ici.

J'ai trouvé un hack qui fonctionne à la fois dans Chrome FF et IE

Le seul problème est que vous devez avoir autant de règles que d'enfants possibles.

L'astuce consiste à définir la flex-direction sur row, définir la flex-base (qui est maintenant la largeur) à 100%, puis traduire les éléments

.container {
    border: solid 2px blue;
    height: 200px;
    width: 200px;
    display: flex;
    flex-direction: column;
    position: relative;
}

.filler {
    border: solid 1px black;
    flex: 0 0 80px;
    background-color: lightgreen;
    transition: flex 1s;
}

.container:hover .filler {
    flex: 0 0 40px;
}

.test {
    border: solid 1px red;
    flex: 1 0 25px;
    display: flex;
    flex-direction: row;
    position: relative;
}

.child {
    background-color: rgba(200, 0, 0, 0.26);
    flex: 0 0 100%; 
}

.child:nth-child(2) {
    background-color: rgba(255, 255, 0, 0.48);
    transform: translateX(-100%) translateY(100%);
}

.child:nth-child(3) {
    background-color: rgba(173, 216, 230, 0.28);
    transform: translateX(-200%) translateY(200%);
}
<div class="container">
    <div class="filler"></div>
    <div class="filler"></div>
    <div class="test">
           <div class="child">1</div>
           <div class="child">2</div>
           <div class="child">3</div>
    </div>
</div>

S'il pouvait y avoir un autre enfant, vous auriez besoin d'une règle du nième enfant (4), etc.

J'ai ajouté un effet de survol pour vérifier comment la taille s'adapte

15
vals

Cela semble être un bug avec Chrome. Similaire à ceux rapportés ici (problème 428049) et peut-être lié à (problème 346275) .

Cela dit :

 - Les navigateurs sont censés résoudre les pourcentages sur l'enfant de l'élément flexible, * si * sa base flexible est définie. 
 - Gecko est * toujours * résolvant les pourcentages indépendamment de la base flexible. 
 - Chrome ne résout * jamais * les pourcentages, quelle que soit la base flexible. 

En résumé, Chrome ne résout pas les pourcentages de hauteur sur l'enfant de flex-item ( même si l'enfant lui-même est un flex-item), contrairement à tous les autres navigateurs.

Cela peut être démontré dans l'extrait ci-dessous: ( violon ici )

* { box-sizing: border-box; margin: 0; padding: 0; }
div.wrap {
    height: 120px; width: 240px; margin: 0px 12px;
    border: 1px solid blue; float: left;
    display: flex; flex-direction: column;    
}
div.parent {
    flex: 0 0 100%;
    border: 1px solid green; 
    display: flex; flex-direction: column;    
}
div.item {
    flex: 0 0 100%;
    border: 1px solid red;
}
<div class="wrap">
    <div class="item">a</div>
    <div class="item">b</div>
    <div class="item">c</div>
</div>
<div class="wrap">
    <div class="parent">
        <div class="item">a</div>
        <div class="item">b</div>
        <div class="item">c</div>
    </div>
</div>

Le second div devrait montrer le même comportement que le premier. Les autres navigateurs (IE11, Edge, FF39) le montrent correctement. Chrome échoue ici et ne résout pas div.item correctement. Il a besoin d'une hauteur fixe sur son parent, sans lequel il utilise min-content comme sa hauteur et ne déborde donc pas.

Alors que, dans le premier div, le div.items sont correctement résolus et débordent en conséquence. En effet, il existe une hauteur fixe sur le parent (c'est-à-dire div.wrap)


Solution possible:

Pour contourner le problème, si vous êtes sûr de ne disposer que de deux éléments (p et div) dans votre wrapper, alors vous pourriez leur donner un 50% la taille. Vous devez fournir un height:50% à ton .column-parent. Chrome a besoin d'une hauteur fixe sur le parent comme illustré ci-dessus.

Ensuite, tout fonctionnera comme vous le souhaitez.

Demo Fiddle: http://jsfiddle.net/abhitalks/kqncm65n/

CSS pertinent:

.wrapper > p { flex: 0 0 50%; }  /* this can be on flex-basis */
.column-parent {
    flex: 1 0 auto; height: 50%; /* but, this needs to be fixed height */
    display: flex; flex-direction: column;
    border: 2px solid blue;
}
.column-child {
    flex: 0 0 100%;              /* this flex-basis is then enough */
    border: 2px solid red;
}

PS: Il semble également y avoir des différences dans le rendu jsfiddle et plnkr. Je ne sais pas pourquoi, mais parfois j'obtiens des résultats différents !

19
Abhitalks

Ma réponse précédente est un hack qui exploite une configuration particulière de la mise en page souhaitée.

Une autre manière, plus générale, de contourner ce Chrome est d'utiliser un élément intermédiaire dans la mise en page et de définir cette taille d'élément en utilisant top: 0px et bottom: 0px. (Au lieu de height) : 100%) Il y a encore un bug dans la manière Chrome gère le calcul, qui a besoin d'une fausse animation pour le faire s'ajuster correctement

.container {
    border: solid 2px blue;
    height: 200px;
    width: 200px;
    display: flex;
    flex-direction: column;
    position: relative;
}

.filler {
    border: solid 1px black;
    flex: 0 0 94px;
    background-color: lightgreen;
    transition: 1s;
}

.container:hover .filler {
    flex: 0 0 50px;
}

.test {
    border: solid 1px red;
    flex: 1 0 25px;
    display: flex;
    flex-direction: row;
    position: relative;
}

@-webkit-keyframes adjust2 {
    0% {flex-basis: 100%;}
  100% {flex-basis: 100.1%;}
}
.child {
    background-color: rgba(200, 0, 0, 0.26);
    width:  100%;
    height: 100%;
    flex: 1 0 100%;
    -webkit-animation: adjust2 1s infinite; /* only needed for webkit bug */
}

.intermediate {
    width:  100%;
    position: absolute;
    top: 0px;
    bottom: 0px;
    display: flex; 
    flex-direction: column; 
}

.child:nth-child(n+2) {
    background-color: rgba(255, 255, 0, 0.48);
}

.child:nth-child(n+3) {
    background-color: rgba(173, 216, 230, 0.28);
}
<div class="container">
    <div class="filler"></div>
    <div class="test">
        <div class="intermediate">
               <div class="child"></div>
               <div class="child"></div>
               <div class="child"></div>
        </div>
    </div>
</div>
10
vals

Qu'en est-il d'ajouter 100% au conteneur:

.column-parent {
  flex: 1 0 100%;
}

Et flex-grow à 1 dans l'élément contenu sans ajuster la base de flex:

.column-child {
  flex: 1 0 0;
}

Voici à quoi cela ressemblerait: http://plnkr.co/edit/H25NQxLtbi65oaltNVax?p=preview

8
E. Serrano