wake-up-neo.com

Wenn Flexbox-Elemente im Spaltenmodus umbrochen werden, vergrößert der Container seine Breite nicht

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):

My desired output

Tatsächliches Ergebnis (was ich bekomme):

My current output

Älteres Ergebnis (was ich 2015 bekommen habe):

My older output

AKTUALISIEREN

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 rowname__, die Breite jedoch nicht im Modus columnname__. Außerdem erfolgt beim Ändern der Höhe eines columnname__-Modus überhaupt kein sofortiger Rückfluss von Elementen, aber im rowname__-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?

UPDATE 2

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.

111
Anders Tornblad

Das Problem

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.


Illustration des Problems

Das OP erstellte eine nützliche Demo, die das Problem veranschaulicht. Ich kopiere es hier: http://jsfiddle.net/nwccdwLw/1/


Umgehungsoptionen

Hacky-Lösungen aus der Stack Overflow-Community:


Weitere Analyse


Andere Beiträge, die dasselbe Problem beschreiben

119
Michael_B

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

2
MandeeD

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. 

  1. Hinzufügen aller Elemente zu einem Container div, der die Elemente mit Flex umwickelt
  2. Das erste Element jedes "inneren Containers" (ich nenne es einen Abschnitt) wird eine Klasse haben, die uns hilft, einige Manipulationen vorzunehmen, die die Trennung und Gestaltung jedes Abschnitts bewirken.
  3. Mit :before für jedes erste Element können wir den Titel jedes Abschnitts ermitteln.
  4. Durch die Verwendung von space wird die Lücke zwischen den Abschnitten erstellt
  5. Da die Variable space 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.
  6. Um die Hintergrundfarbe jedes Abschnitts zu gestalten, füge ich ein weiteres div innerhalb des ersten Elements jedes Abschnitts hinzu. Ich werde auch bei absolut stehen und z-index: -1 haben.
  7. Um die korrekte Breite jedes Hintergrunds zu erhalten, verwende ich JS, stelle die richtige Breite ein und füge einen Listener hinzu, um die Größe zu ändern.

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

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");
     }
}
0
user2323336