Ich arbeite an einem verschachtelten Flexbox-Layout, das wie folgt funktionieren sollte:
Die äußerste Ebene (ul#main
) ist eine horizontale Liste, die nach rechts erweitert werden muss, wenn weitere Elemente hinzugefügt werden. Wenn es zu groß wird, sollte es eine horizontale Bildlaufleiste geben.
#main {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
overflow-x: auto;
/* ...and more... */
}
Jedes Element dieser Liste (ul#main > li
) hat eine Kopfzeile (ul#main > li > h2
) und eine innere Liste (ul#main > li > ul.tasks
). Diese innere Liste ist vertikal und sollte bei Bedarf in Spalten umgebrochen werden. Wenn Sie mehr Spalten einschließen, sollte die Breite zunehmen, um Platz für mehr Elemente zu schaffen. Diese Breitenerhöhung sollte auch für das enthaltende Element der äußeren Liste gelten.
.tasks {
flex-direction: column;
flex-wrap: wrap;
/* ...and more... */
}
Mein Problem ist, dass die inneren Listen nicht umgebrochen werden, wenn die Höhe des Fensters zu klein wird. Ich habe viele Manipulationen an all den Flex-Eigenschaften versucht und versucht, die Richtlinien unter CSS-Tricks genau zu befolgen, aber kein Glück.
Diese JSFiddle zeigt, was ich bisher habe.
Erwartetes Ergebnis (was ich will):
Tatsächliches Ergebnis (was ich bekomme):
Älteres Ergebnis (was ich 2015 bekommen habe):
Nach einigen Nachforschungen scheint dies ein größeres Problem zu sein. Alle gängigen Browser verhalten sich gleich , und es hat nichts damit zu tun, dass mein Flexbox-Design verschachtelt ist. Noch einfachere Flexbox-Spaltenlayouts weigern sich, die Breite der Liste zu erhöhen, wenn die Elemente umbrochen werden.
Diese andere JSFiddle demonstriert das Problem deutlich. In den aktuellen Versionen von Chrome, Firefox und IE11 werden alle Elemente korrekt umbrochen. Die Höhe der Liste erhöht sich im Modus row
name__, die Breite jedoch nicht im Modus column
name__. Außerdem erfolgt beim Ändern der Höhe eines column
name__-Modus überhaupt kein sofortiger Rückfluss von Elementen, aber im row
name__-Modus.
Die offiziellen Angaben (siehe speziell Beispiel 5) scheinen jedoch darauf hinzudeuten, dass das, was ich tun möchte, möglich sein sollte.
Kann jemand eine Lösung für dieses Problem finden?
Nachdem ich viel mit JavaScript experimentiert habe, um die Höhe und Breite verschiedener Elemente während Größenänderungsereignissen zu aktualisieren, bin ich zu dem Schluss gekommen, dass es zu komplex und zu schwierig ist, es auf diese Weise zu lösen. Das Hinzufügen von JavaScript bricht definitiv das Flexbox-Modell, das so sauber wie möglich gehalten werden sollte.
Im Moment greife ich auf overflow-y: auto
anstelle von flex-wrap: wrap
zurück, sodass der innere Container bei Bedarf vertikal gescrollt wird. Es ist nicht schön, aber es ist ein Weg nach vorne, der die Benutzerfreundlichkeit zumindest nicht allzu sehr beeinträchtigt.
Dies scheint ein grundlegender Mangel im Flex-Layout zu sein.
Ein flexibler Container in Spaltenrichtung wird nicht erweitert, um zusätzliche Spalten aufzunehmen. (Dies ist kein Problem in flex-direction: row
.)
Diese Frage wurde oft gestellt (siehe Liste unten), ohne saubere Antworten in CSS.
Es ist schwierig, dies als Fehler zu bezeichnen, da das Problem bei allen gängigen Browsern auftritt. Aber es stellt sich die Frage:
Wie ist es möglich, dass alle gängigen Browser den Flex-Container auf beim Zeilenumbruch in Zeilenrichtung erweitern, aber nicht in Spaltenrichtung?
Sie würden denken, dass mindestens einer von ihnen es richtig machen würde. Ich kann nur über den Grund spekulieren. Vielleicht war es eine technisch schwierige Implementierung und wurde für diese Wiederholung zurückgestellt.
UPDATE: Das Problem scheint in Edge V16 gelöst zu sein.
Das OP erstellte eine nützliche Demo, die das Problem veranschaulicht. Ich kopiere es hier: http://jsfiddle.net/nwccdwLw/1/
Hacky-Lösungen aus der Stack Overflow-Community:
Spät zur Party, aber noch JAHRE später in diese Ausgabe geraten. Endete eine Lösung mit Raster zu finden. Auf dem Container können Sie verwenden
display: grid;
grid-auto-flow: column;
grid-template-rows: repeat(6, auto);
Ich habe ein Beispiel für CodePen, das zwischen dem Flexbox-Problem und dem Raster-Fix wechselt: https://codepen.io/MandeeD/pen/JVLdLd
Da noch keine Lösung oder eine geeignete Problemumgehung vorgeschlagen wurde, konnte ich das angeforderte Verhalten mit einem etwas anderen Ansatz erzielen. Anstatt das Layout in 3 verschiedene Divs zu unterteilen, füge ich alle Elemente zu 1 Div hinzu und erstelle die Trennung mit einigen weiteren Divs dazwischen.
Die vorgeschlagene Lösung ist hart codiert, vorausgesetzt, wir haben drei Abschnitte, können aber auf einen generischen erweitert werden. Die Hauptidee ist zu erklären, wie wir dieses Layout erreichen können.
:before
für jedes erste Element können wir den Titel jedes Abschnitts ermitteln.space
wird die Lücke zwischen den Abschnitten erstelltspace
nicht die volle Höhe des Abschnitts abdeckt, füge ich den Abschnitten auch :after
hinzu und positioniere sie mit absoluter Position und weißem Hintergrund.z-index: -1
haben.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>
Mögliche JS-Lösung ..
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");
}
}