Flexbox: 4 item per baris

260

Saya menggunakan kotak fleksibel untuk menampilkan 8 item yang secara dinamis akan mengubah ukuran dengan halaman saya. Bagaimana saya memaksanya untuk membagi item menjadi dua baris? (4 per baris)?

Ini snip yang relevan:

(Atau jika Anda lebih suka jsfiddle - http://jsfiddle.net/vivmaha/oq6prk1p/2/ )

.parent-wrapper {
  height: 100%;
  width: 100%;
  border: 1px solid black;
}
.parent {
  display: flex;
  font-size: 0;
  flex-wrap: wrap;
  margin: -10px 0 0 -10px;
}
.child {
  display: inline-block;
  background: blue;
  margin: 10px 0 0 10px;
  flex-grow: 1;
  height: 100px;
}
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>

Vivek Maharajh
sumber
16
[Pembaruan] Pertanyaan ini didasarkan pada desain yang tidak responsif. Jika Anda menemukan salah satu jawaban di bawah ini, berhati-hatilah. Dalam desain yang bagus, Anda akan memiliki lebih banyak item di layar yang lebih luas, dan lebih sedikit di layar yang lebih kecil. Memaksa 4 item untuk semua ukuran layar hanya akan terlihat menarik pada rentang lebar layar yang sempit.
Vivek Maharajh

Jawaban:

381

Anda sudah berada flex-wrap: wrapdi wadah. Itu bagus, karena mengesampingkan nilai default, yaitu nowrap( sumber ). Ini adalah alasan item tidak membungkus untuk membentuk kisi dalam beberapa kasus .

Dalam hal ini, masalah utama adalah flex-grow: 1pada item fleksibel.

The flex-growproperti tidak benar-benar ukuran item fleksibel. Tugasnya adalah mendistribusikan ruang kosong dalam wadah ( sumber ). Jadi, sekecil apa pun ukuran layar, setiap item akan menerima bagian proporsional dari ruang kosong di telepon.

Lebih khusus, ada delapan item fleksibel dalam wadah Anda. Dengan flex-grow: 1, masing-masing menerima 1/8 dari ruang kosong di telepon. Karena tidak ada konten di item Anda, mereka dapat menyusut menjadi nol lebar dan tidak akan pernah membungkus.

Solusinya adalah menentukan lebar pada item. Coba ini:

.parent {
  display: flex;
  flex-wrap: wrap;
}

.child {
  flex: 1 0 21%; /* explanation below */
  margin: 5px;
  height: 100px;
  background-color: blue;
}
<div class="parent">
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
</div>

Dengan flex-grow: 1didefinisikan dalam flexsteno, tidak perlu flex-basismenjadi 25%, yang sebenarnya akan menghasilkan tiga item per baris karena margin.

Karena flex-growakan mengkonsumsi ruang kosong di baris, flex-basishanya perlu cukup besar untuk menegakkan bungkus. Dalam hal ini, dengan flex-basis: 21%, ada banyak ruang untuk margin, tetapi tidak pernah cukup ruang untuk item kelima.

Michael Benjamin
sumber
1
Saya suka ini karena itu bekerja untuk saya, tetapi "banyak ruang" membuat saya merasa sedikit tidak nyaman. Apakah ada beberapa jendela kecil atau situasi di mana "estimasi" ini mungkin mengecewakan saya?
Jackson
1
Situasi seperti apa? Di sebagian besar tata letak ada kasus ekstrim yang dapat membuat masalah. Kasus-kasus seperti itu biasanya berlayar melalui analisis biaya-manfaat karena tidak pernah, atau hampir tidak pernah, terjadi. Misalnya, dalam solusi di atas, jika Anda memasukkan margin yang sangat besar, tata letak mungkin pecah. Jika itu masalah, maka itu harus diposting dalam pertanyaan. @Jackson
Michael Benjamin
2
"Jika Anda memasukkan margin yang sangat besar, tata letak mungkin pecah" Itu contoh skenario yang ingin saya hindari. Saya tidak peduli dengan kepraktisan; hibur adorasi saya untuk kesempurnaan. Apakah ada cara untuk lebih tepatnya?
Jackson
27
Anda juga dapat menggunakanflex: 1 0 calc(25% - 10px);
MarkG
2
Jawaban bagus! Perbaikan kecil yang saya gunakan adalah margin: 2%;bukan angka piksel tetap untuk mencegah kotak melompat ke baris baru pada perangkat kecil / resolusi. rumus umum adalah (100 - (4 * box-width-percent)) / 8% untuk lebar kotak yang berbeda
thomaspsk
104

Tambahkan lebar ke .childelemen. Saya pribadi akan menggunakan persentase margin-leftjika Anda ingin selalu 4 per baris.

DEMO

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}
dowomenfart
sumber
Ide bagus. Saya menggunakan ide ini dengan suntingan kecil. jsfiddle.net/vivmaha/oq6prk1p/6
Vivek Maharajh
1
Ah. Ini sebenarnya tidak menyelesaikan masalah saya. Lihat di sini untuk contoh: jsfiddle.net/vivmaha/oq6prk1p/7 . Saya tidak memiliki kebebasan menggunakan persentase untuk margin saya. Mereka harus lebar tetap. Ini berarti bahwa keajaiban 23% yang kami pilih tidak akan berfungsi karena tidak memperhitungkan margin tetap.
Vivek Maharajh
3
Ya, calc menyelesaikannya! 'calc (100% * (1/4) - 10px - 1px)'. Lihat jsfiddle.net/vivmaha/oq6prk1p/9
Vivek Maharajh
24
Lalu apa gunanya flex dalam hal ini?
twicejr
Bagaimana dengan desain responsif? Kami tidak ingin menempatkan lebar tetap pada anak
candjack
40

Ini adalah apporach lain.

Anda dapat melakukannya dengan cara ini juga:

.parent{
  display: flex;
  flex-wrap: wrap;
}

.child{
  width: 25%;
  box-sizing: border-box;
}

Contoh: https://codepen.io/capynet/pen/WOPBBm

Dan contoh yang lebih lengkap: https://codepen.io/capynet/pen/JyYaba

Capy
sumber
1
Bagaimana jika saya memiliki kurang dari 4 anak? Saya tidak suka ruang kosong kosong itu, anak itu tidak responsif ...
candjack
Jawaban lain oleh Muddasir Abbas hanya menggunakan pengaturan fleksibel, jadi saya pikir itu solusi yang lebih bersih.
Andrew Koster
17

Saya akan melakukannya seperti ini menggunakan margin negatif dan kalk untuk talang:

.parent {
  display: flex;
  flex-wrap: wrap;
  margin-top: -10px;
  margin-left: -10px;
}

.child {
  width: calc(25% - 10px);
  margin-left: 10px;
  margin-top: 10px;
}

Demo: https://jsfiddle.net/9j2rvom4/


Metode Kotak CSS Alternatif:

.parent {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

Demo: https://jsfiddle.net/jc2utfs3/

shanomurphy
sumber
14
<style type="text/css">
.parent{
    display: flex;
    flex-wrap: wrap;
}
.parent .child{
    flex: 1 1 25%;
}
</style>    
<div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>

Semoga ini bisa membantu. untuk lebih detail Anda bisa mengikuti tautan ini

Muddasir Abbas
sumber
4

Saya percaya contoh ini lebih barebones dan lebih mudah dipahami daripada @dowomenfart.

.child {
    display: inline-block;
    margin: 0 1em;
    flex-grow: 1;
    width: calc(25% - 2em);
}

Ini menghasilkan perhitungan lebar yang sama sambil memotong langsung ke daging. Matematika lebih mudah dan emmerupakan standar baru karena skalabilitas dan keramahannya pada perangkat seluler.

Joseph Cho
sumber
3
em sebenarnya bukan standar baru. Ini bisa menyebalkan, dan desainer tidak mendesain dengan mempertimbangkan EM.
Danny van Holten
2

.parent-wrapper {
	height: 100%;
	width: 100%;
	border: 1px solid black;
}
	.parent {
	display: flex;
	font-size: 0;
	flex-wrap: wrap;
	margin-right: -10px;
	margin-bottom: -10px;
}
	.child {
	background: blue;
	height: 100px;
	flex-grow: 1;
	flex-shrink: 0;
	flex-basis: calc(25% - 10px);
}
	.child:nth-child(even) {
	margin: 0 10px 10px 10px;
	background-color: lime;
}
	.child:nth-child(odd) {
	background-color: orange; 
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">

	</style>
</head>
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>
</html>

;)

Mateus Manosso Barszcz
sumber
1
Jika Anda dapat menambahkan beberapa konteks tentang mengapa ini menjawab pertanyaan OP daripada hanya memposting kode.
d219
jika Anda menambahkan justify-content: space-evenly;prent, maka mereka menyelaraskan dengan baik dan Anda tidak harus melakukan calcpada anak. Terima kasih untuk contohnya!
Mattijs
0

Bungkus fleksibel + margin negatif

Mengapa fleksibel vs display: inline-block?

Mengapa margin negatif?

Baik Anda menggunakan SCSS atau CSS-in-JS untuk kasus tepi (yaitu elemen pertama dalam kolom), atau Anda menetapkan margin default dan menyingkirkan margin luar nanti.

Penerapan

https://codepen.io/zurfyx/pen/BaBWpja

<div class="outerContainer">
    <div class="container">
        <div class="elementContainer">
            <div class="element">
            </div>
        </div>
        ...
    </div>
</div>
:root {
  --columns: 2;
  --betweenColumns: 20px; /* This value is doubled when no margin collapsing */
}

.outerContainer {
    overflow: hidden; /* Hide the negative margin */
}

.container {
    background-color: grey;
    display: flex;
    flex-wrap: wrap;
    margin: calc(-1 * var(--betweenColumns));
}

.elementContainer {
    display: flex; /* To prevent margin collapsing */
    width: calc(1/var(--columns) * 100% - 2 * var(--betweenColumns));
    margin: var(--betweenColumns);
}

.element {
    display: flex;
    border: 1px solid red;
    background-color: yellow;
    width: 100%;
    height: 42px;
}
zurfyx
sumber
-12

Inilah cara lain tanpa menggunakan calc().

// 4 PER ROW
// 100 divided by 4 is 25. Let's use 21% for width, and the remainder 4% for left & right margins...
.child {
  margin: 0 2% 0 2%;
  width: 21%;
}

// 3 PER ROW
// 100 divided by 3 is 33.3333... Let's use 30% for width, and remaining 3.3333% for sides (hint: 3.3333 / 2 = 1.66666)
.child {
  margin: 0 1.66666% 0 1.66666%;
  width: 30%;
}

// and so on!

Hanya itu yang ada untuk itu. Anda bisa menyukai dimensi untuk mendapatkan ukuran yang lebih estetis tetapi ini adalah idenya.

wle8300
sumber
6
Saya belum menguji ini, tetapi sintaks CSS salah (nilai-nilai CSS tidak dikutip, dan deklarasi harus diakhiri dengan semi-colon) sehingga pasti tidak akan berfungsi dalam bentuk saat ini.
Nick F