Làm cách nào để chỉ định ngắt dòng trong bố cục flexbox nhiều dòng?


236

Có cách nào để ngắt dòng trong flexbox nhiều dòng không?

Ví dụ để phá vỡ sau mỗi mục thứ 3 trong CodePen này .

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

Giống

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

1
Tôi đã có cùng một vấn đề tương tự hoặc rất giống nhau; Tôi muốn phá vỡ mọi mục thứ 4 vì vậy tôi chỉ cần đặt chiều rộng của mỗi mục flex thành 25vw (hoặc 25%). Vì vậy, trong trường hợp của bạn, với mỗi mục thứ 3, bạn sẽ sử dụng 33.3vw (hoặc 33.3%). Làm việc hoàn hảo cho những gì tôi muốn. Có thể giúp đỡ người khác nếu họ đang tìm kiếm một phương pháp đơn giản hơn.
Ben Clarke

Ben Clarke! Cảm ơn bạn rất nhiều! Câu trả lời của bạn là người duy nhất làm việc. Bạn có thể xem xét thêm nó như một câu trả lời. :-)
itmuckel

Câu trả lời:


322

Giải pháp đơn giản và đáng tin cậy nhất là chèn các vật phẩm flex vào đúng chỗ. Nếu chúng đủ rộng ( width: 100%), chúng sẽ buộc ngắt dòng.

Nhưng đó là xấu xí và không ngữ nghĩa. Thay vào đó, chúng ta có thể tạo các phần tử giả bên trong thùng chứa flex và sử dụng orderđể di chuyển chúng đến đúng nơi.

Nhưng có một giới hạn: container flex chỉ có thể có một ::beforevà một ::afterphần tử giả. Điều đó có nghĩa là bạn chỉ có thể buộc 2 ngắt dòng.

Để giải quyết điều đó, bạn có thể tạo các phần tử giả bên trong các mục flex thay vì trong hộp chứa flex. Bằng cách này, bạn sẽ không bị giới hạn ở 2. Nhưng các phần tử giả đó sẽ không phải là mục linh hoạt, vì vậy chúng sẽ không thể buộc ngắt dòng.

Nhưng may mắn thay, CSS Display L3 đã giới thiệu display: contents(hiện chỉ được Firefox 37 hỗ trợ):

Bản thân phần tử không tạo ra bất kỳ hộp nào, nhưng phần tử con và phần tử giả của nó vẫn tạo các hộp như bình thường. Đối với mục đích tạo và bố trí hộp, phần tử phải được xử lý như thể nó đã được thay thế bằng phần tử con và phần tử giả trong cây tài liệu.

Vì vậy, bạn có thể áp dụng display: contentscho trẻ em của hộp chứa flex và bọc nội dung của từng cái bên trong một lớp bọc bổ sung. Sau đó, các mục flex sẽ là các hàm bao bổ sung và các phần tử giả của trẻ em.

Ngoài ra, theo Phân mảnh Flex LayoutCSS Phân mảnh , Flexbox phép buộc phải phá vỡ bằng cách sử dụng break-before, break-afterhoặc CSS 2.1 bí danh của họ:

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

Ngắt dòng cưỡng bức trong flexbox chưa được hỗ trợ rộng rãi, nhưng nó hoạt động trên Firefox.


@Oriol Về cách tiếp cận đầu tiên, tại sao bạn nói nó xấu và không có ngữ nghĩa? Chỉ tò mò thôi.
nacho4d

18
@ nacho4d Vì HTML không nên được sửa đổi cho mục đích tạo kiểu. Và nếu bạn thay đổi quyết định và quyết định bạn muốn 4 cột thay vì 3, bạn sẽ cần sửa đổi rất nhiều HTML. So sánh với break-aftergiải pháp, sẽ chỉ yêu cầu sửa đổi bộ chọn trong biểu định kiểu.
Oriol

1
Tôi cần phải thêm display: block;vào các lớp .container ::before::aftergiả để làm cho giải pháp số hai hoạt động trong IE. YMMV!
đan

1
@twined Điều đó thật lạ, vì các mục flex nên được tự động chặn.
Oriol

2
Vì việc ngắt trang rõ ràng đã bị xóa khỏi thông số kỹ thuật, nên có thể để đoạn mã thứ hai của bạn chạy theo hướng cột và không làm cho nó mở rộng chiều cao của vùng chứa không? Tôi đã không có may mắn và thiết lập cơ sở flex đến 100% / vật phẩm kéo dài chiều cao của nó.
Lucent

42

Theo quan điểm của tôi, việc sử dụng <hr> các yếu tố như ngắt dòng giữa các mục flex là có ý nghĩa hơn .

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

Đã thử nghiệm trong Chrome 66, Firefox 60 và Safari 11.


7
Đây là cách tôi làm nó quá, làm việc tuyệt vời. Thêm hr {flex-cơ sở: 100%; chiều cao: 0; lề: 0; viền: 0; } làm cho sự phá vỡ liền mạch.
Besworks

Tôi thích cách tiếp cận này. Lưu ý: khi sử dụng gap: 10px;khoảng cách giữa các hàng là thực sự 20px. Để giải quyết, chỉ định khoảng cách hàng bằng một nửa kích thước đó : gap: 5px 10px;.
CuddleBunny

@Besworks: bordernên được đặt thành none, thay vì0
Đánh dấu

@mark, border:0;chỉ có giá trị như border:none;. Xem: stackoverflow.com/questions/2922909/ từ
Besworks 15/11/19

23

@Oriol có một câu trả lời tuyệt vời, đáng buồn là vào tháng 10 năm 2017, cả hai đều display:contentskhông page-break-afterđược hỗ trợ rộng rãi, tốt hơn là về Firefox hỗ trợ điều này nhưng không phải những người chơi khác, tôi đã nghĩ ra "hack" sau đây mà tôi cho là tốt hơn khó mã hóa trong một lần ngắt sau mỗi phần tử thứ 3, bởi vì điều đó sẽ làm cho nó rất khó để làm cho trang di động trở nên thân thiện.

Như đã nói, đó là một hack và nhược điểm là bạn cần thêm khá nhiều yếu tố bổ sung để làm gì, nhưng nó thực hiện thủ thuật và hoạt động trên trình duyệt chéo ngay cả trên IE11 ngày.

"Hack" chỉ đơn giản là thêm một yếu tố bổ sung sau mỗi div, được đặt thành display:nonevà sau đó sử dụng css nth-childđể quyết định cái nào trong số này sẽ thực sự hiển thị khi buộc phanh dòng như thế này:

.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
Tôi cũng thấy rằng các phương thức "display: content" và "page-break-after" không hoạt động và đã dùng đến "hack" này. Đây được báo cáo là lỗi Chrome và được đánh dấu là "WontFix" (xem bug.chromium.org/p/chromium/issues/detail?id=473481 ) với lời giải thích: "Có, theo Nhóm làm việc CSS, không cách hiện tại để buộc ngắt dòng trong hộp flex bằng CSS. "
Martin_W

Bạn có thể lưu một liên lạc lộn xộn bằng cách sử dụng bộ chọn .container>p. Sau đó, tất cả các <p></p>thẻ sẽ không cần classthuộc tính. Tất nhiên không quan trọng . Chỉ cần bộ não lười biếng của tôi tìm thấy một tinh chỉnh nhỏ, tiết kiệm không gian cho giải pháp thông minh của bạn. Tất nhiên, nó cũng phụ thuộc vào người dùng không có các <p>thẻ khác là con trực tiếp của .containerdiv. Về mặt kỹ thuật bạn có thể làm tương tự với tất cả các khác <div>trẻ em, nhưng bạn rất nhiều khả năng có khác <div>s trong .containerhơn bạn là <p>s, như vậy có lẽ không phải là một động thái thông minh đó.
Steve

13

Bạn muốn một dòng phá vỡ ngữ nghĩa?

Sau đó xem xét sử dụng <br>. W3Schools có thể gợi ý cho bạn rằng BRchỉ để viết thơ (sắp ra mắt) nhưng bạn có thể thay đổi kiểu để nó hoạt động như một yếu tố khối 100% chiều rộng sẽ đẩy nội dung của bạn sang dòng tiếp theo. Nếu 'br' gợi ý một sự phá vỡ thì nó có vẻ phù hợp với tôi hơn là sử dụng hrhoặc 100% divvà làm cho html dễ đọc hơn.

Chèn <br>nơi bạn cần ngắt dòng và tạo kiểu như thế này.

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

Bạn có thể vô hiệu hóa <br>với các truy vấn phương tiện , bằng cách đặt display:thành blockhoặc nonephù hợp (Tôi đã bao gồm một ví dụ về điều này nhưng để lại nhận xét).

Bạn có thể sử dụng order:để đặt hàng nếu cần quá.

Và bạn có thể đặt bao nhiêu tùy ý, với các lớp hoặc tên khác nhau :-)

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


Không cần giới hạn bản thân với những gì W3Schools nói:

nhập mô tả hình ảnh ở đây


Một phần mở rộng của kỹ thuật là đặt <br class="2col">sau mỗi mục thứ hai, <br class="3col">sau mỗi phần ba. Sau đó, áp dụng một lớp cols-2cho vùng chứa và tạo css để chỉ bật các ngắt dòng thích hợp cho số lượng cột đó. ví dụ. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver

Không, a brkhông dành cho các phần tử ngắt dòng , nó dành cho văn bản : developer.mozilla.org/en-US/docs/Web/HTML/Euity/br ... stackoverflow.com/questions/3937515/
trộm

2
Tôi sẽ thay đổi cách diễn đạt của mình để không trình bày đây là một giải pháp hoàn hảo nhưng trong một số trường hợp tôi không thấy điều này tệ hơn bất kỳ giải pháp phần tử div hoặc giả nào khác. Có lẽ tôi sẽ đi viết một bài thơ về nó bây giờ.
Simon_Weaver

Vâng ... một bài thơ sẽ rất hay, đừng quên đăng một liên kết đến đây :) ... Về một giải pháp hoàn hảo, có một bài ( break-*được hiển thị trong câu trả lời được chấp nhận) mặc dù tiếc là nó chưa đến được trình duyệt chéo , vì vậy, cách tốt nhất thứ hai là sử dụng một yếu tố tự nhiên lấp đầy chiều rộng của cha mẹ và đẩy bất kỳ anh chị em tiếp theo nào đến một hàng của chính họ, một lần nữa được đưa ra trong câu trả lời được chấp nhận. Vì vậy, bằng cách sử dụng bất kỳ yếu tố nào khác ngoài một khối như một khối sẽ tồi tệ hơn, về mặt ngữ nghĩa, như br.
Ason

5
Hãy nhớ rằng, bạn đăng một bản in của W3Schools, không phải W3C, chúng không được kết nối.
Edu Ruiz

7

Tôi nghĩ rằng cách truyền thống là linh hoạt và khá dễ hiểu:

Đánh dấu

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

Tạo tập tin 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;
  }
}

Tôi đã tạo một ví dụ (jsfiddle)

Hãy thử thay đổi kích thước cửa sổ dưới 400px, nó sẽ phản hồi !!


Trong giải pháp này, các yếu tố được kết hợp với nhau, ý tưởng là có một khoảng trống dài giữa chúng.
Juanma Menendez

2

Một giải pháp khả thi khác không yêu cầu thêm bất kỳ đánh dấu bổ sung nào là thêm một số lề động để tách các thành phần.

Trong trường hợp ví dụ, điều này có thể được thực hiện với sự trợ giúp của calc(), chỉ cần thêm margin-leftmargin-rightvào phần tử 3n + 2 (2, 5, 8)

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

Ví dụ đoạn trích

.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
Điều này xứng đáng được bỏ phiếu. Sử dụng kết hợp flex và lề là một cách thực sự đơn giản để hỗ trợ ngắt dòng. Nó cũng hoạt động thực sự tốt với calcnhư được nêu trong câu trả lời này.
stwilz

Tôi thích cái này hơn, chỉ margin-right: 1pxlà vật phẩm, và nó sẽ làm cho vật phẩm tiếp theo bắt đầu ở một hàng mới.
arvil

0

Đối với các câu hỏi trong tương lai, bạn cũng có thể thực hiện bằng cách sử dụng thuộc floattính và xóa nó trong mỗi 3 yếu tố.

Đây là một ví dụ tôi đã thực hiện.

.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
Vấn đề ở đây là OP cho biết giải pháp phải sử dụng flexbox hay display: flex;khôngdisplay: inline-block;
bafromca

1
.cell:nth-child(3n + 1)thay vào đó bạn có thể viết
Si7ius

-1

Tôi đã thử một vài câu trả lời ở đây, và không ai trong số họ làm việc. Trớ trêu thay, những gì đã làm là về sự thay thế đơn giản nhất mà người <br/>ta có thể thử:

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

hoặc bạn cũng có thể làm:

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

Đặt bất cứ nơi nào bạn muốn một dòng mới. Nó dường như hoạt động ngay cả với các liền kề <span>, nhưng tôi đang sử dụng nó với các liền kề <div>.


2
Divs băng thông 100% là giải pháp đầu tiên được đưa ra trong câu trả lời được chấp nhận.
TylerH

1
Đúng, loại. Họ xem thường vì một lý do nghèo nàn (xấu xí, thực sự?). Ngoài ra, câu trả lời của tôi có 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>

bạn có thể thử gói các mục trong một yếu tố dom như ở đây. với điều này bạn không cần phải biết nhiều css chỉ cần có một cấu trúc tốt sẽ giải quyết được vấn đề.


1
Bạn có thể làm cho container trở thành bình thường display: blockvà tạo các flex flex cấp 2 mới đó. Điều này làm việc cho các hàng. Thay thế các div bằng nhịp khi sử dụng chế độ cột.
jiggunjer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.