Flexbox: 4 รายการต่อแถว


260

ฉันใช้เฟล็กบ็อกซ์เพื่อแสดง 8 รายการที่จะปรับขนาดแบบไดนามิกกับหน้าของฉัน ฉันจะบังคับให้แยกรายการออกเป็นสองแถวได้อย่างไร (4 ต่อแถว)?

นี่คือ snip ที่เกี่ยวข้อง:

(หรือถ้าคุณชอบ 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>


16
[อัพเดต] คำถามนี้มีพื้นฐานมาจากการออกแบบที่ไม่ตอบสนองที่ไม่ดี หากคุณพบว่าตัวเองใช้หนึ่งในคำตอบด้านล่างโปรดใช้ความระมัดระวัง ในการออกแบบที่ดีคุณจะมีรายการเพิ่มขึ้นบนหน้าจอที่กว้างขึ้นและน้อยลงบนหน้าจอที่เล็กลง การบังคับให้ 4 รายการสำหรับทุกขนาดหน้าจอจะดูน่าสนใจในช่วงความกว้างของหน้าจอที่แคบ
Vivek Maharajh

คำตอบ:


380

คุณได้รับflex-wrap: wrapบนภาชนะ ดีเพราะมันแทนที่ค่าเริ่มต้นซึ่งก็คือnowrap( แหล่งที่มา ) นี่คือรายการเหตุผลที่ไม่ได้ห่อในรูปแบบตารางในบางกรณี

ในกรณีนี้ปัญหาหลักอยู่flex-grow: 1ในรายการแบบยืดหยุ่น

flex-growคุณสมบัติไม่รายการดิ้นไม่ได้ขนาดจริง หน้าที่ของมันคือการกระจายพื้นที่ว่างในคอนเทนเนอร์ ( แหล่งที่มา ) ดังนั้นไม่ว่าขนาดของหน้าจอจะเล็กเพียงใดรายการแต่ละรายการจะได้รับส่วนที่เป็นสัดส่วนของพื้นที่ว่างในบรรทัด

โดยเฉพาะอย่างยิ่งมีแปดรายการที่ยืดหยุ่นในภาชนะของคุณ ด้วยflex-grow: 1แต่ละคนได้รับ 1/8 ของพื้นที่ว่างในบรรทัด เนื่องจากไม่มีเนื้อหาในรายการของคุณจึงสามารถลดขนาดให้เหลือความกว้างเป็นศูนย์และจะไม่มีการพัน

การแก้ปัญหาคือการกำหนดความกว้างของรายการ ลองสิ่งนี้:

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

เมื่อflex-grow: 1กำหนดไว้ในflexชวเลขไม่จำเป็นต้องflex-basisเป็น 25% ซึ่งจริง ๆ แล้วจะส่งผลให้มีสามรายการต่อแถวเนื่องจากระยะขอบ

เนื่องจากflex-growจะใช้พื้นที่ว่างในแถวflex-basisเพียงอย่างเดียวจึงต้องมีขนาดใหญ่พอที่จะบังคับใช้การตัดคำ ในกรณีนี้flex-basis: 21%มีพื้นที่เหลือสำหรับระยะขอบ แต่ไม่มีที่ว่างเพียงพอสำหรับรายการที่ห้า


1
ฉันชอบสิ่งนี้เพราะมันใช้งานได้สำหรับฉัน แต่ "พื้นที่มากมาย" ทำให้ฉันรู้สึกไม่สบายใจเล็กน้อย มีหน้าต่างเล็ก ๆ หรือสถานการณ์ที่ "การประเมิน" นี้อาจทำให้ฉันล้มเหลวหรือไม่?
Jackson

1
สถานการณ์แบบใด ในเลย์เอาต์ส่วนใหญ่มีหลายกรณีที่สามารถสร้างปัญหาได้ กรณีดังกล่าวมักจะแล่นเรือผ่านการวิเคราะห์ต้นทุนและผลประโยชน์เพราะไม่เคยเกิดขึ้นหรือแทบจะไม่เคยเกิดขึ้นเลย ตัวอย่างเช่นในการแก้ปัญหาข้างต้นหากคุณใส่ระยะขอบที่กว้างมากเค้าโครงอาจแตก หากเป็นปัญหาก็ควรโพสต์ในคำถาม @Jackson
Michael Benjamin

2
“ ถ้าคุณใส่ระยะขอบที่กว้างมากเค้าโครงอาจแตก” นั่นเป็นตัวอย่างของสถานการณ์ที่ฉันต้องการหลีกเลี่ยง ฉันไม่สนใจเรื่องการปฏิบัติจริง ความบันเทิงความรักของฉันเพื่อความสมบูรณ์แบบ มีวิธีใดที่จะแม่นยำมากขึ้น?
Jackson

27
คุณสามารถใช้flex: 1 0 calc(25% - 10px);
MarkG

2
คำตอบที่ดี! การปรับปรุงเล็ก ๆ น้อย ๆ ที่ฉันใช้คือmargin: 2%;แทนที่จะใช้จำนวนพิกเซลคงที่เพื่อป้องกันไม่ให้กล่องกระโดดขึ้นบรรทัดใหม่บนอุปกรณ์ / ความละเอียดขนาดเล็ก สูตรทั่วไปคือ(100 - (4 * box-width-percent)) / 8% สำหรับความกว้างของกล่องที่แตกต่างกัน
thomaspsk

104

เพิ่มความกว้างให้กับ.childองค์ประกอบ ฉันเองจะใช้เปอร์เซ็นต์ในmargin-leftถ้าคุณต้องการให้มันเสมอ 4 ต่อแถว

การสาธิต

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}

ความคิดที่ดี. ฉันใช้ความคิดนี้กับการแก้ไขเล็กน้อย jsfiddle.net/vivmaha/oq6prk1p/6
Vivek Maharajh

1
อา. สิ่งนี้ไม่ได้แก้ปัญหาของฉัน ดูที่นี่สำหรับตัวอย่าง: jsfiddle.net/vivmaha/oq6prk1p/7 ฉันไม่มีอิสระในการใช้เปอร์เซ็นต์สำหรับกำไรของฉัน พวกเขาจะต้องมีความกว้างคงที่ ซึ่งหมายความว่าเวทย์มนตร์ 23% ที่เราเลือกไม่ทำงานเนื่องจากไม่ได้คำนึงถึงระยะขอบคงที่
Vivek Maharajh

3
ใช่ Calc แก้มัน! 'Calc (100% * (1/4) - 10px - 1px)' ดูjsfiddle.net/vivmaha/oq6prk1p/9
Vivek Maharajh

24
ถ้างั้นการใช้เฟล็กซ์ในนี้คืออะไร
ทวีคูณ

แล้วการออกแบบที่ตอบสนองได้ดีล่ะ? เราไม่ต้องการให้ความกว้างคงที่สำหรับเด็ก ๆ
candlejack

40

นี่คืออีกหนึ่ง apporach

คุณสามารถทำได้ด้วยวิธีนี้เช่นกัน:

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

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

ตัวอย่าง: https://codepen.io/capynet/pen/WOPBBm

และตัวอย่างที่สมบูรณ์ยิ่งขึ้น: https://codepen.io/capynet/pen/JyYaba


1
ถ้าฉันมีลูกน้อยกว่า 4 คนล่ะ ฉันไม่ชอบพื้นที่ว่างที่ว่างเปล่าเด็กไม่ตอบสนอง ...
candlejack

คำตอบอื่น ๆ ของ Muddasir Abbas ใช้การตั้งค่าแบบยืดหยุ่นเท่านั้นดังนั้นฉันคิดว่ามันเป็นวิธีที่สะอาด
Andrew Koster

17

ฉันจะทำเช่นนี้โดยใช้ระยะขอบติดลบและคำนวณหารางน้ำ:

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

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

การสาธิต: https://jsfiddle.net/9j2rvom4/


CSS Grid ทางเลือกอื่น:

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

การสาธิต: https://jsfiddle.net/jc2utfs3/


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>

หวังว่ามันจะช่วย สำหรับรายละเอียดเพิ่มเติมคุณสามารถไปที่ลิงค์นี้


4

ฉันเชื่อว่าตัวอย่างนี้เป็นแบร์โบนมากกว่าและเข้าใจได้ง่ายกว่า @dowomenfart

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

การคำนวณความกว้างเดียวกันนี้ประสบความสำเร็จในขณะที่ตัดตรงเข้าเนื้อ คณิตศาสตร์เป็นวิธีที่ง่ายขึ้นและemเป็นมาตรฐานใหม่เนื่องจากความสามารถในการปรับขยายได้และความเป็นมิตรกับมือถือ


3
em ไม่ใช่มาตรฐานใหม่จริงๆ อาจเป็นความเจ็บปวดในตูดและนักออกแบบไม่ได้ออกแบบโดยคำนึงถึง 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>

;)


1
หากคุณสามารถเพิ่มบริบทเกี่ยวกับสาเหตุที่สิ่งนี้ตอบคำถาม OP มากกว่าเพียงแค่โพสต์รหัส
d219

ถ้าคุณเพิ่มjustify-content: space-evenly;ไปยัง prent แล้วพวกเขาจัดอย่างดีและคุณไม่ต้องทำcalcกับเด็ก ขอบคุณสำหรับตัวอย่างแม้ว่า!
Mattijs

0

Flex wrap + margin ติดลบ

ทำไมต้องดิ้นกับdisplay: inline-block?

ทำไมถึงมีกำไรติดลบ

ไม่ว่าคุณจะใช้ SCSS หรือ CSS-in-JS สำหรับกรณีขอบ (เช่นองค์ประกอบแรกในคอลัมน์) หรือคุณตั้งค่าระยะขอบเริ่มต้นและกำจัดขอบด้านนอกในภายหลัง

การดำเนินงาน

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

-12

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!

นั่นคือทั้งหมดที่มีให้มัน คุณสามารถจินตนาการถึงมิติเพื่อให้ได้ขนาดที่สวยงามยิ่งขึ้น แต่นี่เป็นแนวคิด


6
ฉันไม่ได้ทดสอบสิ่งนี้ แต่ไวยากรณ์ CSS ไม่ถูกต้อง (ไม่มีการอ้างอิงค่า CSS และการประกาศควรลงท้ายด้วยเซมิโคลอน) ดังนั้นมันจะไม่ทำงานในรูปแบบปัจจุบัน
Nick F
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.