จะระบุตัวแบ่งบรรทัดในเค้าโครงเฟล็กบ็อกซ์หลายบรรทัดได้อย่างไร?


236

มีวิธีการแบ่งบรรทัดในหลายบรรทัด flexbox หรือไม่

ตัวอย่างเช่นการแตกหลังแต่ละรายการที่ 3 ใน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>

ชอบ

.item:nth-child(3n){
  /* line-break: after; */    
}

1
ฉันมีปัญหาเดียวกันหรือคล้ายกันมาก ฉันต้องการที่จะทำลายทุกรายการที่ 4 ดังนั้นฉันเพิ่งตั้งความกว้างของแต่ละรายการดิ้นเป็น 25vw (หรือ 25%) ดังนั้นในกรณีของคุณสำหรับทุกรายการที่ 3 คุณจะใช้ 33.3vw (หรือ 33.3%) ทำงานอย่างสมบูรณ์แบบสำหรับสิ่งที่ฉันต้องการ อาจช่วยคนอื่นหากพวกเขากำลังมองหาวิธีที่ง่ายกว่า
Ben Clarke

เบ็นคลาร์ก! ขอบคุณมาก! คำตอบของคุณคือคำตอบเดียวที่ได้ผล คุณสามารถลองเพิ่มมันเป็นคำตอบได้ :-)
itmuckel

ที่เกี่ยวข้อง: stackoverflow.com/q/4609279/405017
Phrogz

คำตอบ:


322

ทางออกที่ง่ายที่สุดและน่าเชื่อถือที่สุดคือการใส่เฟล็กซ์ในสถานที่ที่เหมาะสม หากพวกเขากว้างพอ ( width: 100%) พวกเขาจะบังคับให้ขึ้นบรรทัดใหม่

แต่มันก็น่าเกลียดและไม่ใช่ความหมาย แต่เราสามารถสร้างองค์ประกอบหลอกภายใน flex container และใช้orderเพื่อย้ายไปยังตำแหน่งที่ถูกต้อง

แต่มีข้อ จำกัด คือ: flex container สามารถมีได้เฉพาะ::beforeและ::afterองค์ประกอบหลอก นั่นหมายความว่าคุณสามารถบังคับให้แบ่ง 2 บรรทัดเท่านั้น

ในการแก้ปัญหานั้นคุณสามารถสร้างองค์ประกอบเทียมภายในรายการเฟล็กซ์แทนที่จะเป็นในคอนเทนเนอร์เฟล็กซ์ วิธีนี้คุณจะไม่ถูก จำกัด ที่ 2 แต่องค์ประกอบหลอกเหล่านั้นจะไม่เป็นรายการที่ยืดหยุ่นดังนั้นพวกเขาจะไม่สามารถบังคับให้ขึ้นบรรทัดใหม่ได้

แต่โชคดีที่CSS Display L3ได้เปิดตัวdisplay: contents(ปัจจุบันรองรับเฉพาะ Firefox 37):

องค์ประกอบนั้นไม่ได้สร้างกล่องใด ๆ แต่ลูก ๆ และองค์ประกอบหลอกยังคงสร้างกล่องตามปกติ สำหรับวัตถุประสงค์ของการสร้างและเลย์เอาต์องค์ประกอบต้องได้รับการปฏิบัติเสมือนว่ามันถูกแทนที่ด้วยลูก ๆ และองค์ประกอบแบบหลอกในแผนผังเอกสาร

ดังนั้นคุณสามารถนำdisplay: contentsไปใช้กับเด็ก ๆ ของ flex container และห่อเนื้อหาของแต่ละอันไว้ใน wrapper เพิ่มเติม จากนั้นไอเท็มแบบยืดหยุ่นจะเป็นเครื่องห่อเพิ่มเติมและองค์ประกอบแบบหลอกของเด็ก ๆ

อีกทางเลือกหนึ่งตามfragmenting Flex เค้าโครงและCSS Fragmentation , flexbox ช่วยให้การบังคับแบ่งโดยใช้break-before, break-afterหรือ CSS 2.1 นามแฝงของพวกเขา

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

การแบ่งบรรทัดบังคับใน flexbox ยังไม่ได้รับการสนับสนุนอย่างกว้างขวาง แต่สามารถใช้งานได้กับ Firefox


@Oriol เกี่ยวกับวิธีแรกทำไมคุณพูดว่ามันน่าเกลียดและไม่ได้มีความหมาย? แค่สงสัย.
nacho4d

18
@ nacho4d เพราะไม่ควรแก้ไข HTML เพื่อการกำหนดสไตล์ และถ้าคุณเปลี่ยนใจและตัดสินใจว่าคุณต้องการ 4 คอลัมน์แทนที่จะเป็น 3 คุณจะต้องแก้ไข HTML จำนวนมาก เปรียบเทียบกับbreak-afterโซลูชันซึ่งจะต้องแก้ไขตัวเลือกในสไตล์ชีทเท่านั้น
Oriol

1
ฉันต้องการที่จะเพิ่มdisplay: block;ไป.container ::beforeและ::afterหลอกชั้นเรียนที่จะทำให้จำนวนการแก้ปัญหาทั้งสองทำงานใน IE YMMV!
twined

1
@twined มันแปลกเพราะไอเท็มแบบยืดหยุ่นควรถูกบล็อกโดยอัตโนมัติ
Oriol

2
เนื่องจากสิ่งที่แบ่งหน้าถูกลบออกจากข้อมูลจำเพาะเป็นไปได้ไหมที่จะมีข้อมูลโค้ดที่สองของคุณทำงานในทิศทางคอลัมน์และไม่ได้เพิ่มความสูงของคอนเทนเนอร์หรือไม่ ฉันไม่มีโชคและตั้งค่าความยืดหยุ่นเป็น 100% / รายการยืดความสูงของมัน
Lucent

42

จากมุมมองของฉันมันมีความหมายมากกว่าที่จะใช้<hr> องค์ประกอบเป็นตัวแบ่งบรรทัดระหว่างรายการเฟล็กซ์

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

ทดสอบใน Chrome 66, Firefox 60 และ Safari 11


7
นี่คือวิธีที่ฉันทำเช่นกันทำงานได้ดี การเพิ่มชั่วโมง {พื้นฐานยืดหยุ่น: 100%; ความสูง: 0; กำไรขั้นต้น: 0; เส้นขอบ: 0; } ทำให้การแบ่งราบรื่น
Besworks

ฉันชอบวิธีนี้ หมายเหตุ: เมื่อใช้ระยะห่างระหว่างแถวเป็นจริงgap: 10px; ไปยังที่อยู่ระบุช่องว่างแถวของครึ่งหนึ่งของขนาดที่:20px gap: 5px 10px;
CuddleBunny

@Besworks: borderควรจะกำหนดให้noneแทน0
มาร์ค

@ Mark, เป็นเพียงความถูกต้องเป็นborder:0; border:none;ดู: stackoverflow.com/questions/2922909/…
Besworks

23

@Oriol มีคำตอบที่ยอดเยี่ยมน่าเศร้า ณ เดือนตุลาคม 2017 ไม่ใช่display:contentsหรือไม่page-break-afterได้รับการสนับสนุนอย่างกว้างขวางดีกว่าบอกว่ามันเป็นเรื่องของ Firefox ซึ่งสนับสนุนนี้ แต่ไม่ได้เล่นคนอื่น ๆ ผมมีมากับต่อไปนี้ "สับ" ซึ่งผมคิดว่าดีกว่ายาก การเขียนโค้ดหยุดพักหลังจากทุกองค์ประกอบที่ 3 เพราะจะทำให้ยากมากที่จะทำให้หน้าเว็บสำหรับมือถือเป็นมิตร

อย่างที่บอกไปแล้วว่ามันเป็นแฮ็คและข้อเสียคือคุณต้องเพิ่มองค์ประกอบพิเศษมากมายสำหรับสิ่งใด ๆ แต่มันก็ใช้กลอุบายและทำงานข้ามเบราว์เซอร์ได้แม้ใน IE11 ที่ล้าสมัยไปแล้ว

"แฮ็ค" คือการเพิ่มองค์ประกอบเพิ่มเติมหลังจากแต่ละ div ซึ่งถูกตั้งค่าdisplay:noneแล้วใช้ cssnth-childเพื่อตัดสินใจว่าหนึ่งในสิ่งนี้ควรทำให้มองเห็นได้จริง ๆ แล้วบังคับให้ใช้เบรกเส้นแบบนี้:

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


2
ฉันยังพบว่าวิธีการ "แสดงผล: เนื้อหา" และ "หยุดพักหน้าหลัง" ไม่ทำงานและใช้วิธี "แฮ็ค" นี้ สิ่งนี้ได้รับการรายงานว่าเป็นข้อบกพร่องของ Chrome และทำเครื่องหมายว่า "WontFix" (ดูbugs.chromium.org/p/chromium/issues/detail?id=473481 ) พร้อมคำอธิบาย: "มีกลุ่มอ้างอิง CSS Working No วิธีปัจจุบันเพื่อบังคับให้ตัวแบ่งบรรทัดในกล่องเฟล็กซ์ด้วย CSS "
Martin_W

.container>pคุณสามารถประหยัดสัมผัสของความยุ่งเหยิงโดยใช้ตัวเลือก จากนั้น<p></p>แท็กเหล่านั้นทั้งหมดไม่จำเป็นต้องมีclassแอตทริบิวต์ ไม่สำคัญแน่นอน แค่สมองขี้เกียจของฉันค้นหาการปรับแต่งขนาดเล็กที่ประหยัดพื้นที่กับโซลูชันที่ชาญฉลาดของคุณ แน่นอนมันยังขึ้นอยู่กับผู้ใช้ที่ไม่มีอื่น ๆ<p>แท็กเป็นลูกโดยตรงของ.containerdiv เทคนิคที่คุณสามารถทำเช่นเดียวกันกับทุกอื่น ๆ<div>เด็ก ๆ แต่คุณมากขึ้นแนวโน้มที่จะมีคนอื่น ๆ<div>ที่อยู่ใน.containerกว่าที่เป็นอยู่<p>มี s ดังนั้นอาจจะไม่ได้ย้ายมาร์ท
Steve

13

คุณต้องการการหยุดพักแบบ semantic หรือไม่?

<br>แล้วพิจารณาใช้ W3Schools อาจแนะนำคุณว่าBRเป็นเพียงการเขียนบทกวี (ของฉันกำลังจะมาเร็ว ๆ นี้) แต่คุณสามารถเปลี่ยนรูปแบบเพื่อให้มันทำงานเป็นองค์ประกอบบล็อกความกว้าง 100% ที่จะผลักดันเนื้อหาของคุณไปยังบรรทัดถัดไป ถ้า 'br' แสดงให้เห็นว่าตัวแบ่งมันก็เหมาะสมกับฉันมากกว่าการใช้hrหรือ 100% divและทำให้ html อ่านง่ายขึ้น

แทรก<br>ตำแหน่งที่คุณต้องการ linebreaks และจัดรูปแบบเช่นนี้

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

คุณสามารถปิดการใช้งาน<br>ที่มีคำสั่งสื่อโดยการตั้งค่าdisplay:ไปblockหรือnoneตามความเหมาะสม (เราได้รวมตัวอย่างนี้เหลือ แต่มันออกความเห็น)

คุณสามารถใช้order:เพื่อตั้งค่าคำสั่งถ้าจำเป็นเกินไป

และคุณสามารถใส่ได้มากเท่าที่คุณต้องการด้วยคลาสหรือชื่อที่แตกต่างกัน :-)

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


ไม่จำเป็นต้อง จำกัด ตัวเองกับสิ่งที่ W3Schools พูดว่า:

ป้อนคำอธิบายรูปภาพที่นี่


เทคนิคหนึ่งคือการขยาย<br class="2col">ทุกรายการที่สอง<br class="3col">หลังจากทุก ๆ สามวินาที จากนั้นใช้คลาสcols-2กับคอนเทนเนอร์และสร้าง css เพื่อเปิดใช้งานการกระจายบรรทัดที่เหมาะสมสำหรับจำนวนคอลัมน์นั้น เช่น. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver

ไม่ a brไม่ใช่สำหรับองค์ประกอบการแบ่งบรรทัดเป็นข้อความ : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/…
Ason

2
ฉันจะเปลี่ยนคำพูดของฉันเพื่อที่จะไม่ให้สิ่งนี้เป็นโซลูชั่นที่สมบูรณ์แบบ แต่สำหรับบางกรณีฉันไม่เห็นว่านี่เป็นสิ่งที่เลวร้ายยิ่งกว่าวิธีแก้ปัญหาองค์ประกอบ div หรือหลอกอื่น ๆ บางทีฉันจะไปเขียนบทกวีเกี่ยวกับมันตอนนี้
Simon_Weaver

ใช่ ... บทกวีจะดีอย่าลืมโพสต์ลิงค์ไปที่นี่ :) ... เกี่ยวกับโซลูชั่นที่สมบูรณ์มีหนึ่ง ( break-*แสดงในคำตอบที่ยอมรับ) แต่น่าเสียดายที่มันยังไม่ถึงเบราว์เซอร์ข้าม ดังนั้นสิ่งที่ดีที่สุดอันดับสองคือการใช้องค์ประกอบที่เติมความกว้างของพ่อแม่และผลักพี่น้องคนต่อไปให้เป็นแถวของตัวเองซึ่งจะได้รับอีกครั้งในคำตอบที่ยอมรับ ดังนั้นโดยใช้องค์ประกอบอื่น ๆ กว่าบล็อกเหมือนหนึ่งจะเลว, brความหมายเช่น
Ason

5
จำไว้ว่าคุณโพสต์ภาพพิมพ์ของ W3Schools ไม่ใช่ W3C พวกเขาไม่ได้เชื่อมต่อ
Edu Ruiz

7

ฉันคิดว่าวิธีการดั้งเดิมนั้นยืดหยุ่นและง่ายต่อการทำความเข้าใจ:

มาร์กอัป

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

สร้างไฟล์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;
  }
}

ฉันได้สร้างตัวอย่าง (jsfiddle)

พยายามปรับขนาดหน้าต่างภายใต้ 400px มันตอบสนอง !!


ในการแก้ปัญหานี้องค์ประกอบอยู่ด้วยกันความคิดคือการมีช่องว่างยาวระหว่างพวกเขา
Juanma Menendez

2

อีกวิธีที่เป็นไปได้ที่ไม่ต้องการเพิ่มมาร์กอัพพิเศษใด ๆ คือการเพิ่มมาร์จิ้นแบบไดนามิกเพื่อแยกองค์ประกอบ

ในกรณีของตัวอย่างสามารถทำได้ด้วยความช่วยเหลือcalc()เพียงเพิ่มmargin-leftและmargin-rightองค์ประกอบ 3n + 2 (2, 5, 8)

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

ตัวอย่างโค้ด

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


1
นี่สมควรได้รับการโหวต การใช้ flex และ margin ร่วมกันเป็นวิธีที่ง่ายมากในการรองรับการขึ้นบรรทัดใหม่ นอกจากนี้ยังใช้งานได้ดีกับcalcที่ระบุไว้ในคำตอบนี้
stwilz

ฉันชอบสิ่งนี้ดีกว่าเพียงmargin-right: 1pxรายการและมันจะทำให้รายการถัดไปเริ่มต้นที่แถวใหม่
arvil

0

สำหรับคำถามในอนาคตสามารถทำได้โดยใช้ floatคุณสมบัติและล้างมันในแต่ละองค์ประกอบ

นี่คือตัวอย่างที่ฉันทำ

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


3
ปัญหาที่นี่คือ OP ระบุวิธีการแก้ปัญหาต้องใช้ flexbox หรือdisplay: flex;ไม่display: inline-block;
bafromca

1
คุณสามารถเขียน.cell:nth-child(3n + 1)แทน
Si7ius

-1

ฉันลองคำตอบหลายข้อที่นี่และไม่ได้ผลเลย แดกดันสิ่งที่ทำงานเกี่ยวกับทางเลือกที่ง่ายที่สุดที่<br/>จะพยายาม:

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

หรือคุณสามารถทำ:

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

วางที่ทุกที่ที่คุณต้องการขึ้นบรรทัดใหม่ ดูเหมือนว่าการทำงานแม้จะมีที่อยู่ติดกัน<span>'s แต่ฉันใช้มันกับที่อยู่ติดกัน<div>' s


2
ตัวแบ่งความกว้าง 100% เป็นคำตอบแรกที่ให้ในคำตอบที่ยอมรับ
TylerH

1
จริงชนิด พวกเขาดูถูกดูแคลนด้วยเหตุผลที่ไม่ดี (น่าเกลียดจริงเหรอ?) flex-basisนอกจากนี้คำตอบของฉันมี
แอนดรู

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

คุณสามารถลองห่อไอเท็มในองค์ประกอบ dom ได้ที่นี่ ด้วยสิ่งนี้คุณไม่จำเป็นต้องรู้ CSS จำนวนมากเพียงแค่มีโครงสร้างที่ดีจะช่วยแก้ปัญหาได้


1
คุณสามารถสร้างคอนเทนเนอร์ให้เป็นปกติdisplay: blockและสร้าง flexboxes ระดับ 2 เหล่านั้น มันใช้งานได้กับแถว แทนที่ divs ด้วยช่วงเมื่อใช้โหมดคอลัมน์
jiggunjer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.