Wie werden Zeilenumbrüche in einem mehrzeiligen Flexbox-Layout angegeben?

236

Gibt es eine Möglichkeit, einen Zeilenumbruch in einer Flexbox mit mehreren Zeilen zu machen?

Zum Beispiel, um nach jedem dritten Element in diesem CodePen zu brechen .

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
.item:nth-child(3n) {
  background: silver;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

Mögen

.item:nth-child(3n){
  /* line-break: after; */    
}
Artem Svirskyi
quelle
1
Ich hatte das gleiche oder ein sehr ähnliches Problem. Ich wollte jedes 4. Element brechen, also habe ich einfach die Breite jedes Flex-Elements auf 25 VW (oder 25%) eingestellt. In Ihrem Fall würden Sie also für jeden dritten Artikel 33,3 vw (oder 33,3%) verwenden. Arbeitete perfekt für das, was ich wollte. Könnte jemand anderem helfen, wenn er nach einer einfacheren Methode sucht.
Ben Clarke
Ben Clarke! Ich danke dir sehr! Ihre Antwort ist die einzige, die funktioniert hat. Sie könnten es als Antwort hinzufügen. :-)
itmuckel
Siehe auch
Phrogz

Antworten:

322

Die einfachste und zuverlässigste Lösung ist das Einsetzen von Flex-Elementen an den richtigen Stellen. Wenn sie breit genug sind ( width: 100%), erzwingen sie einen Zeilenumbruch.

Aber das ist hässlich und nicht semantisch. Stattdessen könnten wir Pseudoelemente im Flex-Container erzeugen und verwenden order, um sie an die richtigen Stellen zu verschieben.

Es gibt jedoch eine Einschränkung: Der Flex-Container kann nur ein ::beforeund ein ::afterPseudoelement haben. Das heißt, Sie können nur 2 Zeilenumbrüche erzwingen.

Um dies zu lösen, können Sie die Pseudoelemente innerhalb der Flex-Elemente anstatt im Flex-Container generieren. Auf diese Weise sind Sie nicht auf 2 beschränkt. Diese Pseudoelemente sind jedoch keine flexiblen Elemente, sodass sie keine Zeilenumbrüche erzwingen können.

Glücklicherweise hat CSS Display L3 eingeführt display: contents(derzeit nur von Firefox 37 unterstützt):

Das Element selbst generiert keine Boxen, aber seine untergeordneten Elemente und Pseudoelemente generieren weiterhin wie gewohnt Boxen. Für die Boxgenerierung und das Layout muss das Element so behandelt werden, als ob es im Dokumentbaum durch seine untergeordneten Elemente und Pseudoelemente ersetzt worden wäre.

So können Sie sich display: contentsan die Kinder des Flex-Containers wenden und den Inhalt jedes einzelnen in einen zusätzlichen Wrapper einwickeln. Dann sind die flexiblen Elemente diese zusätzlichen Wrapper und die Pseudoelemente der Kinder.

Alternativ kann gemäß Fragmenting Flex - Layout und CSS Fragmentation , ermöglicht Flexbox Brüche unter Verwendung gezwungen break-before, break-afteroder ihre CSS 2.1 Aliase:

.item:nth-child(3n) {
  page-break-after: always; /* CSS 2.1 syntax */
  break-after: always; /* New syntax */
}

Erzwungene Zeilenumbrüche in der Flexbox werden noch nicht allgemein unterstützt, funktionieren jedoch unter Firefox.

Oriol
quelle
@Oriol Über den ersten Ansatz, warum sagst du, es ist hässlich und nicht semantisch? Nur neugierig.
Nacho4d
18
@ nacho4d Da HTML nicht für Stylingzwecke geändert werden sollte. Und wenn Sie Ihre Meinung ändern und entscheiden, dass Sie 4 statt 3 Spalten möchten, müssen Sie möglicherweise viel HTML ändern. Vergleichen Sie mit der break-afterLösung, bei der nur ein Selektor im Stylesheet geändert werden muss.
Oriol
1
Ich musste display: block;die Klassen .container ::beforeund ::afterpseudo hinzufügen , damit die Lösung Nummer zwei im IE funktioniert. YMMV!
Twined
1
@twined Das ist seltsam, weil Flex-Elemente automatisch blockiert werden sollten.
Oriol
2
Ist es möglich, dass Ihr zweites Snippet in Spaltenrichtung ausgeführt wird, ohne dass es die Höhe seines Containers vergrößert, da der Seitenumbruch anscheinend aus der Spezifikation entfernt wurde? Ich hatte kein Glück und die Einstellung der Flex-Basis auf 100% / Gegenstände streckt ihre Höhe.
Lucent
42

Aus meiner Sicht ist es semantischer, <hr> Elemente als Zeilenumbrüche zwischen flexiblen Elementen zu verwenden.

.container {
  display: flex;
  flex-flow: wrap;
}

.container hr {
  width: 100%;
}
<div class="container">
  <div>1</div>
  <div>2</div>
  <hr>
  <div>3</div>
  <div>2</div>
  ...
</div>

Getestet in Chrome 66, Firefox 60 und Safari 11.

Petr Stepanov
quelle
7
So mache ich es auch, funktioniert super. Hinzufügen von hr {Flex-Basis: 100%; Höhe: 0; Rand: 0; Rand: 0; } macht die Pause nahtlos.
Besworks
Ich mag diesen Ansatz. Hinweis: Bei Verwendung ist gap: 10px;der Abstand zwischen den Zeilen tatsächlich 20px. Geben Sie zur Adressierung eine Zeilenlücke an, die halb so groß ist : gap: 5px 10px;.
CuddleBunny
@Besworks: bordersollte eingestellt werden none, anstatt0
Mark
@mark, border:0;ist genauso gültig wie border:none;. Siehe: stackoverflow.com/questions/2922909/…
Besworks
23

@Oriol hat eine ausgezeichnete Antwort, leider seit Oktober 2017, weder display:contents, noch page-break-afterwird weithin unterstützt, besser gesagt, es geht um Firefox, das dies unterstützt, aber nicht um die anderen Spieler. Ich habe mir den folgenden "Hack" ausgedacht, den ich für besser als hart halte Codierung in einer Pause nach jedem 3. Element, da dies es sehr schwierig macht, die Seite mobilfreundlich zu gestalten.

Wie gesagt, es ist ein Hack und der Nachteil ist, dass Sie eine Menge zusätzlicher Elemente für nichts hinzufügen müssen, aber es macht den Trick und funktioniert browserübergreifend sogar auf dem datierten IE11.

Der "Hack" besteht darin, einfach nach jedem Div ein zusätzliches Element hinzuzufügen, das auf gesetzt ist, display:noneund dann mithilfe des CSS nth-childzu entscheiden, welches davon tatsächlich sichtbar gemacht werden soll, um eine Linienbremse wie diese zu erzwingen:

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}
.item:nth-child(3n-1) {
  background: silver;
}
.breaker {display:none;}
.breaker:nth-child(3n) {
  display:block;
  width:100%;
  height:0;
 }
<div class="container">
  <div class="item">1</div><p class=breaker></p>
  <div class="item">2</div><p class=breaker></p>
  <div class="item">3</div><p class=breaker></p>
  <div class="item">4</div><p class=breaker></p>
  <div class="item">5</div><p class=breaker></p>
  <div class="item">6</div><p class=breaker></p>
  <div class="item">7</div><p class=breaker></p>
  <div class="item">8</div><p class=breaker></p>
  <div class="item">9</div><p class=breaker></p>
  <div class="item">10</div><p class=breaker></p>
</div>

Emil Borconi
quelle
2
Ich fand auch heraus, dass die Methoden "display: content" und "page-break-after" nicht funktionieren, und griff auf diesen "Hack" zurück. Dies wurde als Chrome-Fehler gemeldet und als "WontFix" (siehe bugs.chromium.org/p/chromium/issues/detail?id=473481 ) mit der Erklärung markiert : "Laut CSS-Arbeitsgruppe gibt es keine Aktuelle Methode zum Erzwingen eines Zeilenumbruchs in einer Flexbox mit CSS. "
Martin_W
Mit dem Selektor können Sie einen Hauch von Unordnung sparen .container>p. Dann würden all diese <p></p>Tags das classAttribut nicht benötigen . Natürlich nicht wichtig . Nur mein fauler Kopf findet eine winzige, platzsparende Optimierung Ihrer cleveren Lösung. Natürlich hängt es auch davon ab, dass der Benutzer keine anderen <p>Tags als direkte .containeruntergeordnete Elemente des div hat. Technisch gesehen könnten Sie das Gleiche mit allen anderen <div>Kindern tun , aber es ist viel wahrscheinlicher, dass Sie andere <div>in der Schule haben .containerals Sie <p>, also wahrscheinlich kein kluger Schachzug.
Steve
13

Sie möchten einen semantischen Zeilenumbruch?

Dann erwägen Sie die Verwendung <br>. W3Schools schlägt Ihnen möglicherweise vor, BRnur Gedichte zu schreiben (meins kommt bald), aber Sie können den Stil so ändern, dass er sich wie ein Blockelement mit 100% Breite verhält, das Ihren Inhalt in die nächste Zeile bringt. Wenn 'br' eine Pause vorschlägt, erscheint es mir angemessener als die Verwendung von hroder 100% divund macht das HTML lesbarer.

Fügen Sie die Stelle ein, <br>an der Sie Zeilenumbrüche benötigen, und gestalten Sie sie so.

 // Use `>` to avoid styling `<br>` inside your boxes 
 .container > br 
 {
    width: 100%;
    content: '';
 }

Sie können Medienabfragen deaktivieren<br> , indem Sie sie display:auf blockoder nonenach Bedarf einstellen (ich habe ein Beispiel dafür beigefügt, es jedoch auskommentiert).

Bei Bedarf können Sie auch order:die Reihenfolge festlegen.

Und du kannst so viele setzen, wie du willst, mit verschiedenen Klassen oder Namen :-)

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}

.container > br
{
  width: 100%;
  content: '';
}

// .linebreak1 
// { 
//    display: none;
// }

// @media (min-width: 768px) 
// {
//    .linebreak1
//    {
//       display: block;
//    }
// }
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <br class="linebreak1"/>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>


Sie müssen sich nicht auf das beschränken, was W3Schools sagt:

Geben Sie hier die Bildbeschreibung ein

Simon_Weaver
quelle
Eine Erweiterung der Technik besteht darin, <br class="2col">nach jedem zweiten Gegenstand <br class="3col">nach jedem dritten zu setzen. cols-2Wenden Sie dann eine Klasse auf den Container an und erstellen Sie CSS, um nur die entsprechenden Zeilenumbrüche für diese Anzahl von Spalten zu aktivieren. z.B. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver
Nein, ein brnicht für Zeilenumbrüche Elemente , ist es für Text : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/...
Ason
2
Ich werde meinen Wortlaut ändern, um dies nicht als perfekte Lösung darzustellen, aber in einigen Fällen sehe ich dies nicht als schlechter an als andere Div- oder Pseudoelementlösungen. Vielleicht schreibe ich jetzt ein Gedicht darüber.
Simon_Weaver
Ja ... ein Gedicht wäre schön, vergessen Sie nicht, hier einen Link dazu zu posten :) ... In Bezug auf eine perfekte Lösung gibt es eine ( break-*in der akzeptierten Antwort gezeigt), obwohl sie leider noch keine Cross-Browser erreicht hat Das zweitbeste ist also, ein Element zu verwenden, das die Breite seiner Eltern nativ ausfüllt und alle nächsten Geschwister in eine Reihe von sich selbst schiebt, was wiederum in der akzeptierten Antwort angegeben ist. Wenn Sie also ein anderes Element als einen Block wie einen verwenden, wäre dies semantisch schlechter als der br.
Ason
5
Denken Sie daran, dass Sie einen Ausdruck von W3Schools veröffentlichen, nicht von W3C. Sie sind nicht verbunden.
Edu Ruiz
7

Ich denke, der traditionelle Weg ist flexibel und ziemlich leicht zu verstehen:

Markup

<div class="flex-grid">
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>

    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>

    <div class="col-3">.col-3</div>
    <div class="col-9">.col-9</div>

    <div class="col-6">.col-6</div>
    <div class="col-6">.col-6</div>
</div>

Erstellen Sie die Datei grid.css :

.flex-grid {
  display: flex;
  flex-flow: wrap;
}

.col-1 {flex: 0 0 8.3333%}
.col-2 {flex: 0 0 16.6666%}
.col-3 {flex: 0 0 25%}
.col-4 {flex: 0 0 33.3333%}
.col-5 {flex: 0 0 41.6666%}
.col-6 {flex: 0 0 50%}
.col-7 {flex: 0 0 58.3333%}
.col-8 {flex: 0 0 66.6666%}
.col-9 {flex: 0 0 75%}
.col-10 {flex: 0 0 83.3333%}
.col-11 {flex: 0 0 91.6666%}
.col-12 {flex: 0 0 100%}

[class*="col-"] {
  margin: 0 0 10px 0;

  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

@media (max-width: 400px) {
  .flex-grid {
    display: block;
  }
}

Ich habe ein Beispiel erstellt (jsfiddle)

Versuchen Sie, die Größe des Fensters unter 400px zu ändern, es reagiert!

Moshe Quantz
quelle
Bei dieser Lösung sind die Elemente zusammen, die Idee ist, einen langen Leerraum zwischen ihnen zu haben.
Juanma Menendez
2

Eine andere mögliche Lösung, bei der kein zusätzliches Markup hinzugefügt werden muss, besteht darin, einen dynamischen Rand hinzuzufügen, um die Elemente zu trennen.

Im Fall des Beispiels kann dies mit Hilfe des einfachen calc()Hinzufügens margin-leftund margin-rightzum 3n + 2-Element (2, 5, 8) erfolgen.

.item:nth-child(3n+2) {
  background: silver;
  margin: 10px calc(50% - 175px);
}

Snippet-Beispiel

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
.item:nth-child(3n+2) {
  background: silver;
  margin: 10px calc(50% - 175px);
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

Juanma Menendez
quelle
1
Dies verdient eine Abstimmung. Die Verwendung einer Kombination aus Flex und Rand ist eine sehr einfache Möglichkeit, Zeilenumbrüche zu unterstützen. Es funktioniert auch sehr gut mit, calcwie in dieser Antwort beschrieben.
stwilz
Mir gefällt das besser, nur margin-right: 1pxder Artikel, und der nächste Artikel beginnt in einer neuen Zeile.
Arvil
0

Bei zukünftigen Fragen ist es auch möglich, die floatEigenschaft zu verwenden und sie in jeweils drei Elementen zu löschen.

Hier ist ein Beispiel, das ich gemacht habe.

.grid {
  display: inline-block;
}

.cell {
  display: inline-block;
  position: relative;
  float: left;
  margin: 8px;
  width: 48px;
  height: 48px;
  background-color: #bdbdbd;
  font-family: 'Helvetica', 'Arial', sans-serif;
  font-size: 14px;
  font-weight: 400;
  line-height: 20px;
  text-indent: 4px;
  color: #fff;
}

.cell:nth-child(3n) + .cell {
  clear: both;
}
<div class="grid">
  <div class="cell">1</div>
  <div class="cell">2</div>
  <div class="cell">3</div>
  <div class="cell">4</div>
  <div class="cell">5</div>
  <div class="cell">6</div>
  <div class="cell">7</div>
  <div class="cell">8</div>
  <div class="cell">9</div>
  <div class="cell">10</div>
</div>

Gabriel
quelle
3
Das Problem hier ist das OP angegeben, dass die Lösung Flexbox verwenden muss oder display: flex;nichtdisplay: inline-block;
bafromca
1
Sie können schreiben als .cell:nth-child(3n + 1)stattdessen
Si7ius
-1

Ich habe hier mehrere Antworten ausprobiert, und keine davon hat funktioniert. Ironischerweise ging es bei der Arbeit um die einfachste Alternative zu einem <br/>Versuch:

<div style="flex-basis: 100%;"></div>

oder Sie könnten auch tun:

<div style="width: 100%;"></div>

Platzieren Sie das, wo immer Sie eine neue Linie wollen. Es scheint sogar mit Nachbarn zu funktionieren <span>, aber ich benutze es mit Nachbarn <div>.

Andrew
quelle
2
Divs mit 100% Breite sind die erste Lösung, die in der akzeptierten Antwort angegeben ist.
TylerH
1
Stimmt, irgendwie. Sie werden aus einem schlechten Grund herabgesehen (wirklich hässlich?). Auch meine Antwort hat flex-basis.
Andrew
-4

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}

.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
<div class="container">
  <div>
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>
  <div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
  </div>
  <div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
  </div>
  <div class="item">10</div>
</div>

Sie können versuchen, die Elemente wie hier in ein dom-Element zu verpacken. mit diesem müssen Sie nicht viel CSS wissen, nur eine gute Struktur wird das Problem lösen.

Naseeruddin VN
quelle
1
Sie könnten Container zu einem normalen Container machen display: blockund diese neuen Tier-2-Divs-Flexboxen erstellen. Dies funktioniert für Zeilen. Ersetzen Sie die Divs durch Spans, wenn Sie den Spaltenmodus verwenden.
Jiggunjer