web-dev-qa-db-fra.com

Lorsque les éléments de la boîte souple se terminent en mode colonne, la largeur du conteneur n’augmente pas

Je travaille sur une disposition imbriquée de flexbox qui devrait fonctionner comme suit:

Le niveau le plus externe (ul#main) est une liste horizontale qui doit être développée à droite lorsque plusieurs éléments y sont ajoutés. Si elle devient trop grande, il devrait y avoir une barre de défilement horizontale.

#main {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    /* ...and more... */
}

Chaque élément de cette liste (ul#main > li) a un en-tête (ul#main > li > h2) et une liste interne (ul#main > li > ul.tasks). Cette liste interne est verticale et doit être insérée dans des colonnes si nécessaire. Lorsque vous enroulez dans plus de colonnes, sa largeur devrait augmenter pour laisser de la place à plus d'éléments. Cette augmentation de largeur devrait s'appliquer également à l'élément contenant de la liste externe.

.tasks {
    flex-direction: column;
    flex-wrap: wrap;
    /* ...and more... */
}

Mon problème est que les listes intérieures ne sont pas bouclées lorsque la hauteur de la fenêtre devient trop petite. J'ai essayé beaucoup de manipuler toutes les propriétés de flex en essayant de suivre méticuleusement les instructions données par CSS-Tricks , mais sans succès.

Ce JSFiddle montre ce que j'ai jusqu'à présent.

Résultat attendu (ce que je veux)}:

My desired output

Résultat réel (ce que je reçois)}:

My current output

Ancien résultat (ce que j'ai eu en 2015)}:

My older output

METTRE À JOUR

Après une enquête, cela commence à ressembler à un problème plus important. Tous les principaux navigateurs se comportent de la même manière , et cela n'a rien à voir avec l'imbrication de ma conception de flexbox. Même les dispositions de colonnes flexbox les plus simples refusent d'augmenter la largeur de la liste lorsque les éléments sont renvoyés à la ligne.

Ce autre JSFiddle montre clairement le problème. Dans les versions actuelles de Chrome, Firefox et IE11, tous les éléments sont correctement emballés. la hauteur de la liste augmente en mode row, mais sa largeur n'augmente pas en mode column. De plus, il n'y a pas de reflux immédiat des éléments lors du changement de hauteur d'un mode column, mais il y en a en mode row.

Cependant, les official specs (regardez spécifiquement l'exemple 5)} semblent indiquer que ce que je veux faire devrait être possible.

Quelqu'un peut-il proposer une solution de contournement à ce problème?

MISE À JOUR 2

Après de nombreuses expériences d'utilisation de JavaScript pour mettre à jour la hauteur et la largeur de divers éléments lors d'événements de redimensionnement, je suis parvenu à la conclusion qu'il était trop complexe et trop compliqué d'essayer de le résoudre de cette façon. En outre, l'ajout de JavaScript rompt définitivement le modèle de boîte flexible, qui doit rester aussi propre que possible.

Pour l'instant, je retombe à overflow-y: auto au lieu de flex-wrap: wrap afin que le conteneur interne défile verticalement lorsque cela est nécessaire. Ce n’est pas beau, mais c’est une voie à suivre qui au moins ne nuit pas trop à la facilité d’utilisation.

111
Anders Tornblad

Le problème

Cela ressemble à une lacune fondamentale de la mise en page flexible.

Un conteneur flexible dans le sens des colonnes ne sera pas étendu pour accueillir des colonnes supplémentaires. (Ce n'est pas un problème dans flex-direction: row.)

Cette question a été posée à plusieurs reprises (voir liste ci-dessous), sans réponses claires en CSS.

Il est difficile de considérer cela comme un bogue, car le problème survient sur tous les principaux navigateurs. Mais cela soulève la question:

Comment est-il possible que tous les principaux navigateurs utilisent le conteneur flex pour développer l'enveloppe dans le sens des lignes mais pas dans le sens des colonnes?

Vous penseriez au moins un d'entre eux réussirait. Je ne peux que spéculer sur la raison. C'était peut-être une implémentation techniquement difficile et a été mise de côté pour cette itération.

UPDATE: Le problème semble être résolu dans Edge v16.


Illustration du problème

Le PO a créé une démonstration utile illustrant le problème. Je le copie ici: http://jsfiddle.net/nwccdwLw/1/


Options de contournement

Solutions piratées de la communauté Stack Overflow:


Plus d'analyse


Autres messages décrivant le même problème

119
Michael_B

En retard à la fête, mais courait toujours dans ce problème ans plus tard. A fini par trouver une solution en utilisant la grille. Sur le conteneur, vous pouvez utiliser

display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(6, auto);

J'ai un exemple sur CodePen qui bascule entre le problème de flexbox et le correctif de grille: https://codepen.io/MandeeD/pen/JVLdLd

2
MandeeD

Comme aucune solution ou solution de contournement appropriée n'a encore été suggérée, j'ai réussi à obtenir le comportement souhaité avec une approche légèrement différente. Au lieu de séparer la mise en page en 3 div différents, j'ajoute tous les éléments dans 1 div et crée la séparation avec quelques divs supplémentaires.

La solution proposée est codée en dur, en supposant que nous ayons 3 sections, mais peut être étendue à une section générique. L'idée principale est d'expliquer comment nous pouvons réaliser cette mise en page. 

  1. Ajout de tous les éléments dans 1 conteneur div qui utilise flex pour envelopper les éléments
  2. Le premier élément de chaque "conteneur interne" (je l'appellerai une section) aura une classe, ce qui nous aidera à faire quelques manipulations qui créent la séparation et le style de chaque section.
  3. En utilisant :before sur chaque premier élément, nous pouvons localiser le titre de chaque section.
  4. Utiliser space crée un espace entre les sections
  5. Etant donné que space ne couvrira pas toute la hauteur de la section, j’ajoute également :after aux sections afin de la positionner avec une position absolue et un fond blanc.
  6. Pour styler la couleur d'arrière-plan de chaque section, j'ajoute un autre div à l'intérieur du premier élément de chaque section. Je serai aussi en position absolue avec z-index: -1.
  7. Pour obtenir la largeur correcte de chaque arrière-plan, j'utilise JS, en définissant la largeur correcte et en ajoutant un écouteur à redimensionner.

function calcWidth() {
  var size = $(document).width();
  var end = $(".end").offset().left;

  var todoWidth = $(".doing-first").offset().left;
  $(".bg-todo").css("width", todoWidth);

  var doingWidth = $(".done-first").offset().left - todoWidth;
  $(".bg-doing").css("width", doingWidth);

  var doneWidth = $(".end").offset().left - $(".done-first").offset().left;
  $(".bg-done").css("width", doneWidth + 20);

}

calcWidth();

$(window).resize(function() {
  calcWidth();
});
.container {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  height: 120px;
  align-content: flex-start;
  padding-top: 30px;
  overflow-x: auto;
  overflow-y: hidden;
}

.item {
  width: 200px;
  background-color: #e5e5e5;
  border-radius: 5px;
  height: 20px;
  margin: 5px;
  position: relative;
  box-shadow: 1px 1px 5px 0px rgba(0, 0, 0, 0.75);
  padding: 5px;
}

.space {
  height: 150px;
  width: 10px;
  background-color: #fff;
  margin: 10px;
}

.todo-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "To Do (2)";
  font-weight: bold;
}

.doing-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "Doing (5)";
  font-weight: bold;
}

.doing-first:after,
.done-first:after {
  position: absolute;
  top: -35px;
  left: -25px;
  width: 10px;
  height: 180px;
  z-index: 10;
  background-color: #fff;
  content: "";
}

.done-first:before {
  position: absolute;
  top: -30px;
  height: 30px;
  content: "Done (3)";
  font-weight: bold;
}

.bg-todo {
  position: absolute;
  background-color: #FFEFD3;
  width: 100vw;
  height: 150px;
  top: -30px;
  left: -10px;
  z-index: -1;
}

.bg-doing {
  position: absolute;
  background-color: #EFDCFF;
  width: 100vw;
  height: 150px;
  top: -30px;
  left: -15px;
  z-index: -1;
}

.bg-done {
  position: absolute;
  background-color: #DCFFEE;
  width: 10vw;
  height: 150px;
  top: -30px;
  left: -15px;
  z-index: -1;
}

.end {
  height: 150px;
  width: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">

  <div class="item todo-first">
    <div class="bg-todo"></div>
    Drink coffee
  </div>
  <div class="item">Go to work</div>

  <div class="space"></div>

  <div class="item doing-first">
    <div class="bg-doing"></div>
    1
  </div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>

  <div class="space"></div>

  <div class="item done-first">
    <div class="bg-done"></div>
    1
  </div>
  <div class="item">2</div>
  <div class="item">3</div>

  <div class="end"></div>

</div>

0
Itay Gal

Solution JS possible ..

var ul = $("ul.ul-to-fix");

if(ul.find("li").length>{max_possible_rows)){
    if(!ul.hasClass("width-calculated")){
        ul.width(ul.find("li").eq(0).width()*ul.css("columns"));
        ul.addClass("width-calculated");
     }
}
0
user2323336