Bagaimana cara menentukan jeda baris dalam tata letak flexbox multi-baris?

236

Apakah ada cara untuk membuat garis terputus dalam beberapa saluran flexbox?

Misalnya untuk istirahat setelah setiap item ke-3 dalam CodePen ini .

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

Suka

.item:nth-child(3n){
  /* line-break: after; */    
}
Artem Svirskyi
sumber
1
Saya memiliki masalah yang sama atau sangat mirip; Saya ingin memecah setiap item ke-4 jadi saya hanya mengatur lebar setiap item flex ke 25vw (atau 25%). Jadi dalam kasus Anda, untuk setiap item ke-3 Anda akan menggunakan 33.3vw (atau 33,3%). Bekerja dengan sempurna untuk apa yang saya inginkan. Mungkin bisa membantu orang lain jika mereka mencari metode yang lebih sederhana.
Ben Clarke
Ben Clarke! Terima kasih banyak! Jawaban Anda adalah satu-satunya yang berhasil. Anda dapat mempertimbangkan untuk menambahkannya sebagai jawaban. :-)
itmuckel

Jawaban:

322

Solusi paling sederhana dan paling dapat diandalkan adalah memasukkan item fleksibel di tempat yang tepat. Jika mereka cukup lebar ( width: 100%), mereka akan memaksa garis putus.

Tapi itu jelek dan tidak semantik. Sebagai gantinya, kita bisa membuat elemen pseudo di dalam wadah fleksibel, dan menggunakannya orderuntuk memindahkannya ke tempat yang tepat.

Tetapi ada batasan: wadah fleksibel hanya dapat memiliki ::beforedan ::afterelemen pseudo. Itu berarti Anda hanya dapat memaksa 2 jeda baris.

Untuk mengatasinya, Anda dapat membuat elemen pseudo di dalam item fleksibel alih-alih dalam wadah fleksibel. Dengan cara ini Anda tidak akan terbatas pada 2. Tetapi elemen-elemen semu itu tidak akan menjadi item fleksibel, sehingga mereka tidak akan dapat memaksa jeda baris.

Namun untungnya, CSS Display L3 telah diperkenalkan display: contents(saat ini hanya didukung oleh Firefox 37):

Elemen itu sendiri tidak menghasilkan kotak apa pun, tetapi anak-anak dan elemen semu masih menghasilkan kotak seperti biasa. Untuk keperluan pembuatan dan tata letak kotak, elemen harus diperlakukan seolah-olah telah diganti dengan anak-anak dan elemen semu di pohon dokumen.

Jadi Anda bisa menerapkannya display: contentspada anak-anak wadah fleksibel, dan bungkus masing-masing isi bungkus tambahan. Kemudian, item fleksibel adalah pembungkus tambahan dan elemen pseudo anak-anak.

Atau, menurut Fragmenting Flex Layout dan CSS Fragmentation , Flexbox memungkinkan pemutusan paksa dengan menggunakan break-before, break-afteratau alias CSS 2.1 mereka:

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

Pemutusan saluran secara paksa di flexbox belum didukung secara luas, tetapi bekerja pada Firefox.

Oriol
sumber
@ Oriol Tentang pendekatan pertama, mengapa Anda mengatakan itu jelek dan tidak semantik? Hanya penasaran.
nacho4d
18
@ nacho4d Karena HTML tidak boleh dimodifikasi untuk keperluan styling. Dan jika Anda berubah pikiran dan memutuskan ingin 4 kolom, bukan 3, Anda perlu memodifikasi mungkin banyak HTML. Bandingkan dengan break-aftersolusinya, yang hanya membutuhkan modifikasi pemilih dalam stylesheet.
Oriol
1
Saya perlu menambahkan display: block;ke kelas .container ::beforedan ::afterpseudo untuk membuat solusi nomor dua berfungsi di IE. YMMV!
dipintal
1
@twined Itu aneh, karena item flex harus diblokir secara otomatis.
Oriol
2
Karena hal pemecah-halaman tampaknya dihapus dari spek, apakah mungkin untuk membuat potongan kedua Anda berjalan ke arah kolom dan tidak membuatnya memperluas ketinggian wadahnya? Saya tidak beruntung dan menetapkan basis flex hingga 100% / item membentang tingginya.
Lucent
42

Dari perspektif saya itu lebih semantik untuk menggunakan <hr> elemen sebagai garis istirahat antara item fleksibel.

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

Diuji di Chrome 66, Firefox 60 dan Safari 11.

Petr Stepanov
sumber
7
Ini adalah bagaimana saya melakukannya juga, bekerja dengan baik. Menambahkan jam {basis-fleksibel: 100%; tinggi: 0; margin: 0; perbatasan: 0; } membuat istirahat mulus.
Besworks
Saya suka pendekatan ini. Catatan: saat menggunakan gap: 10px;jarak antar baris sebenarnya 20px. Untuk alamat, menentukan kesenjangan deretan setengah ukuran bahwa: gap: 5px 10px;.
CuddleBunny
@Besworks: borderharus di set ke none, alih-alih0
Tandai
@mark, sama validnya border:0;dengan border:none;. Lihat: stackoverflow.com/questions/2922909/…
Besworks
23

@Oriol memiliki jawaban yang sangat bagus, sayangnya pada Oktober 2017, tidak display:contentsjugapage-break-after didukung secara luas, lebih baik mengatakan ini tentang Firefox yang mendukung ini tetapi bukan pemain lain, saya telah datang dengan "hack" berikut yang saya anggap lebih baik daripada sulit mengkode dalam istirahat setelah setiap elemen ke-3, karena itu akan membuatnya sangat sulit untuk membuat halaman mobile friendly.

Seperti yang dikatakan itu adalah peretasan dan kelemahannya adalah Anda perlu menambahkan cukup banyak elemen tambahan untuk apa-apa, tetapi ia melakukan trik dan bekerja lintas peramban bahkan pada IE11 tanggal.

"Retasan" adalah dengan menambahkan elemen tambahan setelah setiap div, yang diatur ke display:nonedan kemudian menggunakan css nth-childuntuk memutuskan yang mana dari ini yang benar-benar harus dibuat terlihat memaksa rem garis seperti ini:

.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
sumber
2
Saya juga menemukan bahwa metode "display: content" dan "page-break-after" tidak berfungsi, dan beralih ke "hack" ini. Ini dilaporkan sebagai bug Chrome, dan ditandai sebagai "WontFix" (lihat bugs.chromium.org/p/chromium/issues/detail?id=473481 ) dengan penjelasan: "Ada, menurut Kelompok Kerja CSS, tidak ada cara saat ini untuk memaksa pemutusan garis dalam kotak fleksibel dengan CSS. "
Martin_W
Anda dapat menyimpan sedikit sentuhan dengan menggunakan pemilih .container>p. Maka semua <p></p>tag itu tidak perlu classatribut. Tentu tidak penting . Hanya otak malas saya menemukan tweak kecil hemat-ruang untuk solusi pintar Anda. Tentu saja, itu juga bergantung pada pengguna yang tidak memiliki <p>tag lain sebagai anak langsung dari .containerdiv. Secara teknis Anda bisa melakukan hal yang sama dengan semua lainnya <div>anak-anak, tapi kau banyak lebih mungkin untuk memiliki lain <div>s dalam .containerdari Anda <p>s, jadi mungkin bukan langkah yang cerdas di sana.
Steve
13

Anda ingin linebreak semantik?

Kemudian pertimbangkan untuk menggunakan <br>. W3Schools mungkin menyarankan Anda BRhanya untuk menulis puisi (punyaku akan segera datang) tetapi Anda dapat mengubah gaya sehingga berperilaku sebagai elemen blok 100% lebar yang akan mendorong konten Anda ke baris berikutnya. Jika 'br' menyarankan istirahat maka tampaknya lebih tepat bagi saya daripada menggunakan hratau 100% divdan membuat html lebih mudah dibaca.

Masukkan di <br>mana Anda perlu linebreak dan beri style seperti ini.

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

Anda dapat menonaktifkan <br>dengan kueri media , dengan menyetel display:ke blockatau nonesebagaimana mestinya (saya telah menyertakan contoh ini tetapi tidak berkomentar).

Anda dapat menggunakan order:untuk mengatur pesanan jika diperlukan juga.

Dan Anda dapat menempatkan sebanyak yang Anda inginkan, dengan kelas atau nama yang berbeda :-)

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


Tidak perlu membatasi diri dengan apa yang dikatakan W3Schools:

masukkan deskripsi gambar di sini

Simon_Weaver
sumber
Salah satu perluasan teknik adalah menempatkan <br class="2col">setelah setiap item kedua, <br class="3col">setelah setiap ketiga. Kemudian menerapkan kelas cols-2ke wadah dan membuat css hanya memungkinkan linebreak yang sesuai untuk jumlah kolom itu. misalnya. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver
Tidak, a brbukan untuk elemen pemecah baris , itu untuk teks : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/…
Ason
2
Saya akan mengubah kata-kata saya agar tidak menyajikan ini sebagai solusi yang sempurna tetapi untuk beberapa kasus saya tidak melihat ini sebagai yang lebih buruk daripada solusi elemen div atau pseudo elemen lainnya. Mungkin aku akan menulis puisi tentang itu sekarang.
Simon_Weaver
Ya ... sebuah puisi akan menyenangkan, jangan lupa untuk memposting tautan di sini :) ... Mengenai solusi yang sempurna, ada satu ( break-*ditampilkan dalam jawaban yang diterima) meskipun sayangnya belum mencapai browser lintas belum , jadi yang terbaik kedua adalah menggunakan elemen yang secara native mengisi lebar induknya dan mendorong saudara kandung berikutnya ke barisan mereka sendiri, yang lagi-lagi diberikan dalam jawaban yang diterima. Jadi dengan menggunakan elemen lain selain blok seperti itu akan lebih buruk, semantik, seperti br.
Ason
5
Ingat, Anda memposting cetakan W3Schools, bukan W3C, mereka tidak terhubung.
Edu Ruiz
7

Saya pikir cara tradisional itu fleksibel dan cukup mudah dimengerti:

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>

Buat file 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;
  }
}

Saya telah membuat contoh (jsfiddle)

Cobalah untuk mengubah ukuran jendela di bawah 400px, responsif !!

Moshe Quantz
sumber
Dalam solusi ini unsur-unsurnya bersama, idenya adalah untuk memiliki ruang kosong yang panjang di antara mereka.
Juanma Menendez
2

Solusi lain yang mungkin tidak perlu menambahkan markup tambahan adalah menambahkan margin dinamis untuk memisahkan elemen.

Dalam kasus contoh, ini dapat dilakukan dengan bantuan calc(), cukup menambahkan margin-leftdan margin-rightke elemen 3n + 2 (2, 5, 8)

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

Contoh cuplikan

.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
sumber
1
Ini layak mendapat suara. Menggunakan kombinasi flex dan margin adalah cara yang sangat sederhana untuk mendukung jeda baris. Ini juga bekerja dengan sangat baik dengan calcsebagaimana diuraikan dalam jawaban ini.
stwilz
Saya suka ini lebih baik, hanya margin-right: 1pxitem, dan itu akan membuat item berikutnya dimulai pada baris baru.
arvil
0

Untuk pertanyaan di masa mendatang, Anda juga dapat melakukannya dengan menggunakan float properti dan membersihkannya di setiap 3 elemen.

Ini contoh yang saya buat.

.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
sumber
3
masalahnya di sini adalah OP menyatakan solusinya harus menggunakan flexbox atau display: flex;, tidakdisplay: inline-block;
bafromca
1
Anda dapat menulis sebagai .cell:nth-child(3n + 1)gantinya
Si7ius
-1

Saya mencoba beberapa jawaban di sini, dan tidak ada yang berhasil. Ironisnya, apa yang berhasil adalah tentang alternatif paling sederhana yang <br/>bisa dilakukan seseorang:

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

atau Anda juga bisa melakukan:

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

Tempatkan itu di mana pun Anda inginkan jalur baru. Tampaknya berfungsi bahkan dengan yang berdekatan <span>, tapi saya menggunakannya dengan yang berdekatan <div>.

Andrew
sumber
2
100%-bandwidth divs adalah solusi pertama yang diberikan dalam jawaban yang diterima.
TylerH
1
Benar, agak. Mereka dipandang rendah karena alasan yang buruk (jelek, benarkah?). Juga, jawaban saya sudah 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>

Anda bisa mencoba membungkus item dalam elemen dom seperti di sini. dengan ini Anda tidak perlu tahu banyak css hanya dengan memiliki struktur yang baik akan menyelesaikan masalah.

Naseeruddin VN
sumber
1
Anda bisa membuat wadah menjadi normal display: blockdan membuat kotak 2 divs flexbox baru. Ini berfungsi untuk baris. Ganti div dengan rentang saat menggunakan mode kolom.
jiggunjer