Jak określić podziały linii w wieloliniowym układzie Flexbox?

236

Czy istnieje sposób na przerwanie linii w wielu liniach Flexbox?

Na przykład, aby złamać po każdym 3. elemencie w CodePen .

.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>

Lubić

.item:nth-child(3n){
  /* line-break: after; */    
}
Artem Svirskyi
źródło
1
Miałem ten sam lub bardzo podobny problem; Chciałem złamać co 4 pozycję, więc po prostu ustawiłem szerokość każdego elementu flex na 25vw (lub 25%). Tak więc w twoim przypadku na każdy 3 element użyłbyś 33,3% wag. (Lub 33,3%). Działa idealnie dla tego, czego chciałem. Może pomóc komuś innemu, jeśli szuka prostszej metody.
Ben Clarke
Ben Clarke! Dziękuję bardzo! Twoja odpowiedź jest jedyną, która zadziałała. Możesz rozważyć dodanie go jako odpowiedzi. :-)
itmuckel

Odpowiedzi:

322

Najprostszym i najbardziej niezawodnym rozwiązaniem jest wstawianie elementów elastycznych we właściwych miejscach. Jeśli są wystarczająco szerokie ( width: 100%), wymuszą przerwanie linii.

Ale to brzydkie i nie semantyczne. Zamiast tego możemy wygenerować pseudoelementy wewnątrz elastycznego kontenera i użyćorder do przeniesienia ich we właściwe miejsca.

Ale nie jest to ograniczenie: flex pojemnik może mieć tylko ::beforei jak ::afterpseudo-element. Oznacza to, że możesz wymusić tylko 2 łamanie linii.

Aby rozwiązać ten problem, możesz wygenerować pseudoelementy wewnątrz elementów elastycznych zamiast w kontenerze elastycznym. W ten sposób nie będziesz ograniczony do 2. Ale te pseudoelementy nie będą elementami elastycznymi, więc nie będą w stanie wymusić przerwania linii.

Ale na szczęście CSS Display L3 wprowadził display: contents(obecnie obsługiwane tylko przez Firefoksa 37):

Sam element nie generuje żadnych pól, ale jego elementy potomne i pseudoelementy nadal generują pola jak zwykle. Do celów generowania i układu ramki element należy traktować tak, jakby został zastąpiony elementami potomnymi i pseudoelementami w drzewie dokumentu.

Możesz więc zastosować display: contentsdo elementów podrzędnych elastycznego pojemnika i zawinąć zawartość każdego z nich w dodatkowe opakowanie. Następnie elementami elastycznymi będą te dodatkowe opakowania i pseudoelementy dzieci.

Alternatywnie, według fragmentacji Flex Układ i CSS Fragmentacja , schematu flexbox umożliwia wymuszone przerwy za pomocą break-before, break-afterlub ich CSS 2.1 aliasów:

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

Wymuszone podziały linii w Flexbox nie są jeszcze powszechnie obsługiwane, ale działa w przeglądarce Firefox.

Oriol
źródło
@Oriol Jeśli chodzi o pierwsze podejście, dlaczego mówisz, że jest brzydkie, a nie semantyczne? Po prostu ciekawy.
nacho4d
18
@ nacho4d Ponieważ HTML nie powinien być modyfikowany do celów stylizacji. A jeśli zmienisz zdanie i zdecydujesz, że chcesz 4 kolumny zamiast 3, musisz zmodyfikować może wiele HTML. Porównaj z break-afterrozwiązaniem, które wymagałoby jedynie modyfikacji selektora w arkuszu stylów.
Oriol,
1
Musiałem dodać display: block;do .container ::beforei ::afterpseudo klas, aby liczba Rozwiązanie drugie działa w IE. YMMV!
twined
1
@twined To dziwne, ponieważ elementy flex powinny być automatycznie blokowane.
Oriol,
2
Ponieważ element podziału strony został najwyraźniej usunięty ze specyfikacji, czy możliwe jest uruchomienie drugiego fragmentu kodu w kierunku kolumny i nie zwiększanie wysokości kontenera? Nie miałem szczęścia i ustawienie flex-base na 100% / przedmioty rozciągają się na wysokość.
Lucent
42

Z mojej perspektywy bardziej semantyczne jest używanie <hr> elementów jako podziałów linii między elementami elastycznymi.

.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>

Testowane w Chrome 66, Firefox 60 i Safari 11.

Petr Stepanov
źródło
7
Tak też to robię, działa świetnie. Dodanie godziny {elastyczna podstawa: 100%; wysokość: 0; margines: 0; granica: 0; } sprawia, że ​​przerwa jest płynna.
Besworks
Lubię to podejście. Uwaga: podczas korzystania gap: 10px;z odległości między rzędami jest w rzeczywistości 20px. Adres, określ odstęp wiersza połowę tej wielkości: gap: 5px 10px;.
CuddleBunny
@Besworks: bordernależy ustawić na none, zamiast0
Mark
Znak @ border:0;jest tak samo ważny jak border:none;. Zobacz: stackoverflow.com/questions/2922909/…
Besworks
23

@Oriol ma doskonałą odpowiedź, niestety od października 2017 r., Ani display:contents, anipage-break-after jest szeroko obsługiwany, lepiej powiedzieć, że chodzi o Firefox, który obsługuje to, ale nie inne odtwarzacze, wymyśliłem następujący „hack”, który uważam za lepszy niż trudny kodowanie z przerwą po każdym trzecim elemencie, ponieważ bardzo utrudni to dostosowanie strony do urządzeń mobilnych.

Jak już powiedziano, jest to hack, a wadą jest to, że musisz dodać całkiem sporo dodatkowych elementów za darmo, ale robi to sztuczkę i działa w różnych przeglądarkach nawet w datowanym IE11.

„Hack” polega po prostu na dodaniu dodatkowego elementu po każdym div, który jest ustawiony na, display:nonea następnie użył css, nth-childaby zdecydować, który z nich powinien być rzeczywiście widoczny, wymuszając hamulec linii taki jak ten:

.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
źródło
2
Odkryłem również, że metody „display: content” i „page-break-after” nie działają, i zastosowałem ten „hack”. Zostało to zgłoszone jako błąd przeglądarki Chrome i oznaczony jako „WontFix” (patrz bugs.chromium.org/p/chromium/issues/detail?id=473481 ) z wyjaśnieniem: „Według grupy roboczej CSS nie ma obecny sposób wymuszenia przerwania linii w polu elastycznym za pomocą CSS. ”
Martin_W
Za pomocą wybieraka możesz zaoszczędzić trochę bałaganu .container>p. Wtedy wszystkie te <p></p>tagi nie potrzebowałyby tego classatrybutu. Nie ważne, oczywiście. Tylko mój leniwy mózg znajduje drobny, zajmujący mało miejsca drobiazg do twojego sprytnego rozwiązania. Oczywiście zależy to również od tego, czy użytkownik nie ma innych <p>znaczników jako bezpośrednich potomków .containerdiv. Technicznie można zrobić to samo z innymi <div>dziećmi, ale jesteś o wiele bardziej prawdopodobne, że inne <div>sw .containerniż ty <p>s, więc prawdopodobnie nie jest to mądry ruch tam.
Steve,
13

Chcesz semantyczny podział linii?

Następnie rozważ użycie <br>. W3Schools może sugerować, że BRto tylko do pisania wierszy (moje już wkrótce), ale możesz zmienić styl, aby zachowywał się jak element blokowy o szerokości 100%, który popchnie twoją treść do następnego wiersza. Jeśli „br” sugeruje przerwę, to wydaje mi się bardziej odpowiednie niż używanie hrlub 100% divi sprawia, że ​​HTML jest bardziej czytelny.

Wstaw miejsce, w <br>którym potrzebujesz podziałów linii, i stylizuj go w ten sposób.

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

Możesz wyłączyć za <br>pomocą zapytań o media , ustawiając display:na blocklub noneodpowiednio (podałem przykład tego, ale zostawiłem komentarz).

W order:razie potrzeby możesz użyć, aby ustawić kolejność.

I możesz umieścić tyle, ile chcesz, z różnymi klasami lub nazwami :-)

.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>


Nie musisz ograniczać się do tego, co mówi W3Schools:

wprowadź opis zdjęcia tutaj

Simon_Weaver
źródło
Jednym przedłużeniem techniki jest umieszczanie <br class="2col">co drugi element, <br class="3col">co trzeci. Następnie zastosuj klasę cols-2do kontenera i utwórz css, aby włączyć tylko odpowiednie łamanie wierszy dla tej liczby kolumn. na przykład. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver
Nie, a brnie jest przeznaczone do elementów łamania linii , tylko do tekstu : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/
Ason
2
Zmienię moje sformułowania, aby nie przedstawiać tego jako idealnego rozwiązania, ale w niektórych przypadkach nie uważam tego za gorsze niż inne rozwiązania div lub pseudoelementowe. Może teraz napiszę o tym wiersz.
Simon_Weaver
Tak ... wiersz byłby fajny, nie zapomnij opublikować tutaj linku :) ... Jeśli chodzi o idealne rozwiązanie, jest jeden ( break-*pokazany w zaakceptowanej odpowiedzi), ale niestety nie dotarł on już do różnych przeglądarek , więc drugim najlepszym rozwiązaniem jest użycie elementu, który natywnie wypełnia szerokość rodzica i wypycha kolejne rodzeństwo do rzędu siebie, co znowu jest podane w zaakceptowanej odpowiedzi. Zatem użycie dowolnego elementu innego niż blok, takiego jak jeden, byłoby gorsze, semantycznie, jak br.
Ason
5
Pamiętaj, że publikujesz wydruk W3Schools, a nie W3C, nie są one połączone.
Edu Ruiz,
7

Myślę, że tradycyjny sposób jest elastyczny i dość łatwy do zrozumienia:

Narzut

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

Utwórz plik 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;
  }
}

Stworzyłem przykład (jsfiddle)

Spróbuj zmienić rozmiar okna poniżej 400 pikseli, jest responsywny !!

Moshe Quantz
źródło
W tym rozwiązaniu elementy są razem, chodzi o to, aby między nimi była długa pusta przestrzeń.
Juanma Menendez
2

Innym możliwym rozwiązaniem, które nie wymaga dodawania żadnych dodatkowych znaczników, jest dodanie dynamicznego marginesu w celu oddzielenia elementów.

W przypadku tego przykładu można to zrobić calc(), dodając margin-lefti dodając margin-rightelement 3n + 2 (2, 5, 8)

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

Przykład fragmentu

.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
źródło
1
To zasługuje na głosowanie. Użycie kombinacji flexu i marginesu jest naprawdę prostym sposobem na wsparcie łamania linii. Działa to również bardzo dobrze, calcjak opisano w tej odpowiedzi.
stwilz
Bardziej mi się to podoba, tylko margin-right: 1pxprzedmiot i sprawi, że następny element zacznie od nowego wiersza.
arvil
0

W przypadku przyszłych pytań można to również zrobić za pomocą float właściwości i usuwając ją z każdego 3 elementów.

Oto przykład, który stworzyłem.

.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
źródło
3
problem polega na tym, że OP stwierdził, że rozwiązanie musi używać Flexboksa display: flex;, a niedisplay: inline-block;
bafromca,
1
możesz .cell:nth-child(3n + 1)zamiast tego napisać
Si7ius,
-1

Próbowałem tutaj kilku odpowiedzi i żadna z nich nie zadziałała. Jak na ironię, to, co zadziałało, było najprostszą alternatywą dla <br/>jednej z możliwych:

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

lub możesz także:

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

Umieść to w dowolnym miejscu nowej linii. Wydaje się, że działa nawet z sąsiednimi <span>, ale używam go z sąsiednimi <div>.

Andrzej
źródło
2
Działy 100% szerokości są pierwszym rozwiązaniem podanym w zaakceptowanej odpowiedzi.
TylerH
1
To prawda. Patrzy się na nich z nieszczęśliwego powodu (brzydko, naprawdę?). Moja odpowiedź brzmi również 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>

możesz spróbować zawinąć elementy w element dom, taki jak tutaj. z tym nie musisz wiedzieć dużo css tylko posiadanie dobrej struktury rozwiąże problem.

Naseeruddin VN
źródło
1
Możesz uczynić kontener normalnym display: blocki uczynić te nowe Flexboxy div 2 poziomu. Działa to dla wierszy. W trybie kolumnowym zamień div na rozpiętości.
jiggunjer