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)}:
Résultat réel (ce que je reçois)}:
Ancien résultat (ce que j'ai eu en 2015)}:
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?
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.
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.
Le PO a créé une démonstration utile illustrant le problème. Je le copie ici: http://jsfiddle.net/nwccdwLw/1/
Solutions piratées de la communauté Stack Overflow:
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
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.
:before
sur chaque premier élément, nous pouvons localiser le titre de chaque section.space
crée un espace entre les sectionsspace
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.z-index: -1
.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>
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");
}
}