Як вказати розриви рядків у багаторядковому макеті флекси?


236

Чи є спосіб зробити розрив лінії в декількох лініях флексбоксу?

Наприклад, для перерви після кожного 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%). Працював ідеально для того, що я хотів. Може допомогти комусь іншому, якщо вони шукають більш простий метод.
Бен Кларк

Бен Кларк! Дуже дякую! Ваша відповідь єдина, яка спрацювала. Ви можете розглянути, як додати його як відповідь. :-)
itmuckel

Відповіді:


322

Найпростішим і надійним рішенням є вставлення гнучких предметів у потрібні місця. Якщо вони досить широкі ( width: 100%), вони змусять перервати лінію.

Але це потворно і не смислово. Натомість ми можемо генерувати псевдоелементи всередині контейнера flex і використовувати їх orderдля переміщення в потрібні місця.

Але є обмеження: контейнер flex може мати лише a ::beforeі a::after псевдоелемент. Це означає, що ви можете примусити лише 2 перерви лінії

Щоб вирішити це, ви можете генерувати псевдоелементи всередині елементів flex, а не в контейнері flex. Таким чином ви не обмежуватиметесь 2. Але ці псевдоелементи не будуть гнучкими елементами, тому вони не зможуть примусити розривів рядків.

Але на щастя, CSS Display L3 представивdisplay: contents (на даний момент підтримується лише Firefox 37):

Сам елемент не генерує жодних коробок, але його дочірні та псевдоелементи все ще генерують поля як звичайні. Для створення генерації та компонування, елемент повинен розглядатися так, ніби він був замінений його дочірніми та псевдоелементами у дереві документів.

Таким чином, ви можете застосувати display: contentsдо дітей гнучку ємність і загортати вміст кожного з них всередину додаткової обгортки. Тоді гнучкими предметами стануть ті додаткові обгортки та псевдоелементи дітей.

Крім того , в відповідно до фрагментуються Flex Layout і CSS фрагментація , 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 */
}

Примусові перерви у флексбоксі ще не підтримуються широко, але це працює на Firefox.


@Oriol Про перший підхід, чому ти кажеш, що це некрасиво, а не семантично? Просто цікаво.
nacho4d

18
@ nacho4d Оскільки HTML не слід змінювати для цілей стилізації. І якщо ви передумаєте і вирішите, що хочете 4 колонки замість 3, вам потрібно буде змінити, можливо, багато HTML. Порівняйте з break-afterрішенням, яке вимагало б лише змінити селектор у таблиці стилів.
Оріол

1
Мені потрібно було додати display: block;до класів .container ::beforeі ::afterпсевдо, щоб рішення номер два працювало в IE. YMMV!
покручений

1
@twined Це дивно, адже гнучкі елементи повинні блокуватися автоматично.
Оріол

2
Оскільки предмет розриву сторінки, очевидно, був видалений із специфікації, чи можна запустити другий фрагмент у напрямку стовпця, а не розширити його висоту контейнера? Мені не пощастило і встановлення флекс-бази на 100% / елементи розтягують її висоту.
Луцент

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
Ось як я це теж роблю, чудово працює. Додавання hr {flex-бази: 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.

"Злом" полягає в тому, щоб просто додати додатковий елемент після кожного діва, який встановлюється, display:noneа потім використовувати css, nth-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
Я також встановив, що методи "display: content" та "break-after" не працюють, і вдався до цього "зламу". Про це повідомлялося як про помилку Chrome і позначено як "WontFix" (див. Bugs.chromium.org/p/chromium/isissue/detail?id=473481 ) з поясненням: "За даними Робочої групи CSS, немає поточний спосіб примусити перерву лінії у гнучкому полі з CSS. "
Martin_W

Ви можете врятувати шматочок безладу, використовуючи селектор .container>p. Тоді всі ці <p></p>теги не потребували б classатрибуту. Не важливо, звичайно. Просто мій ледачий мозок знайшов крихітний, економію простору твій розумний варіант. Звичайно, він також покладається на те, що користувач не має інших <p>тегів як прямих дітей .containerдива. Технічно ви могли б зробити те ж саме з усіма іншими <div>дітьми, але у вас набагато більше шансів на те, <div>що у .containerвас є інші s, ніж ви <p>, тому, ймовірно, не розумний хід.
Стів

13

Хочеш семантичного рядка?

Потім розглянути питання про використання <br>. W3Schools можуть підказати вам, що BRце саме для написання віршів (моє незабаром), але ви можете змінити стиль, щоб він поводився як елемент блоку на 100% ширини, який підштовхне ваш вміст до наступного рядка. Якщо 'br' пропонує перерву, то мені здається більш підходящим, ніж використання hrабо 100%div і робить html більш читабельним.

Вставте <br>туди, де вам потрібні перерви в рядку, і оформіть її так.

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

Ні, а brне для елементів розриву рядків , це для тексту : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/…
Ason

2
Я зміню своє формулювання, щоб не представляти це як ідеальне рішення, але в деяких випадках я не вважаю це гіршим, ніж інші рішення діва чи псевдоелементів. Можливо, зараз піду написати вірш про це.
Simon_Weaver

Так ... вірш було б добре, не забудьте опублікувати тут посилання :) ... Щодо ідеального рішення, є таке ( break-*показано у прийнятій відповіді), хоча, на жаль, воно ще не досягло перехресних браузерів. , тож другим найкращим є використання елемента, який споконвічно заповнює ширину свого батька і підштовхує будь-якого наступного побратима до себе ряду, який знову дається у прийнятій відповіді. Отже, використовуючи будь-який інший елемент, крім блоку на зразок одного, було б гірше, семантично, як br.
Асон

5
Пам'ятайте, що ви розміщуєте друк W3Schools, а не W3C, вони не пов'язані.
Еду Руїс

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, воно чуйне !!


У цьому рішенні елементи разом, ідея полягає у тому, щоб між ними був довгий порожній простір.
Хуанма Менендес

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елемент, і він змусить наступний елемент починати з нового рядка.
арвіль

0

Для майбутніх питань це також можна зробити, використовуючи float властивістю та очистивши її в кожному з 3 елементів.

Ось приклад, який я зробив.

.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
Проблема тут полягає в тому, що ОП заявило, що рішення має використовувати флексбокс або 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>, але я використовую це із суміжними <div>.


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і зробити ці нові флексбокси нового рівня 2. Це працює для рядків. Під час використання режиму стовпців замініть діви на проміжки.
jiggunjer
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.