Как указать разрывы строк в многострочном макете flexbox?

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,3 кВт (или 33,3%). Работал отлично для того, что я хотел. Может помочь кому-то еще, если они ищут более простой метод.
Бен Кларк,
Бен Кларк! Спасибо вам большое! Ваш ответ единственный, который сработал. Вы можете добавить его в качестве ответа. :-)
itmuckel
Связанный: stackoverflow.com/q/4609279/405017
Phrogz

Ответы:

323

Самое простое и надежное решение - вставлять гибкие элементы в нужных местах. Если они достаточно широкие ( width: 100%), они вызовут разрыв строки.

Но это некрасиво и не семантически. Вместо этого мы могли бы генерировать псевдоэлементы внутри flex-контейнера и использовать их orderдля перемещения в нужные места.

Но есть ограничение: гибкий контейнер может иметь только псевдоэлемент ::beforeи ::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 */
}

Принудительные разрывы строк во flexbox пока широко не поддерживаются, но это работает в Firefox.

Ориоль
источник
@Oriol О первом подходе, почему вы говорите, что это уродливо и не семантически? Просто любопытно.
nacho4d
18
@ nacho4d Потому что HTML не должен изменяться в целях стилизации. И если вы передумаете и решите, что вам нужно 4 столбца вместо 3, вам придется изменить, возможно, много HTML. Сравните с break-afterрешением, которое потребует только изменения селектора в таблице стилей.
Oriol
1
Мне нужно добавить display: block;к .container ::beforeи ::afterпсевдо классам , чтобы сделать номер два решения работы в IE. YMMV!
скрутил
1
@twined Это странно, потому что гибкие элементы должны блокироваться автоматически.
Oriol
2
Поскольку элемент разрыва страницы, очевидно, был удален из спецификации, возможно ли заставить ваш второй фрагмент работать в направлении столбца и не позволить ему увеличить высоту своего контейнера? Мне не повезло и установка flex-base на 100% / items растягивает его высоту.
Lucent
42

С моей точки зрения более семантически использовать <hr> элементы как разрывы строк между элементами flex.

.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-based: 100%; высота: 0; поле: 0; граница: 0; } делает перерыв без шва.
Besworks
Мне нравится этот подход. Примечание: при использовании gap: 10px;расстояние между рядами на самом деле 20px. Для адреса, указать разрыв строки половины этого размера: gap: 5px 10px;.
CuddleBunny
@Besworks: borderдолжен быть установлен noneвместо0
Mark
@mark, border:0;так же, как и border:none;. См .: stackoverflow.com/questions/2922909/…
Besworks
23

У @Oriol отличный ответ, к сожалению, по состоянию на октябрь 2017 года, ни тот display:contents, ни другой page-break-afterшироко не поддерживаются, лучше сказать, что это Firefox, который поддерживает это, но не других игроков, я придумал следующий «взлом», который я считаю лучше, чем сложный кодирование в перерыве после каждого третьего элемента, потому что это сделает очень трудным сделать страницу удобной для мобильного.

Как уже говорилось, это взлом, и недостатком является то, что вам нужно добавить довольно много дополнительных элементов, но это работает и работает в разных браузерах даже на устаревшем IE11.

«Хаком» является простое добавление дополнительного элемента после каждого элемента div, который устанавливается 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: contents» и «page-break-after» не работают, и прибег к этому «хаку». Это было сообщено как ошибка Chrome и помечено как «WontFix» (см. Bugs.chromium.org/p/chromium/issues/detail?id=473481 ) с объяснением: «По мнению рабочей группы CSS, нет текущий способ заставить разрыв строки в гибкой коробке с помощью CSS. "
Martin_W
Вы можете сохранить ощущение беспорядка, используя селектор .container>p. Тогда всем этим <p></p>тегам не понадобится classатрибут. Не важно конечно. Просто мой ленивый мозг нашел крошечный, экономящий место твой хитрый способ решения. Конечно, он также полагается на то, что пользователь не имеет других <p>тегов как прямых потомков .containerdiv. Технически вы могли бы сделать то же самое со всеми другими <div>детьми, но вы гораздо более вероятно, есть и другие <div>ю.ш. в .containerчем вас <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:

введите описание изображения здесь

Simon_Weaver
источник
Одно расширение техники - ставить <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
Я изменю свою формулировку, чтобы не представлять это как идеальное решение, но в некоторых случаях я не вижу в этом ничего хуже, чем другие решения для div или псевдоэлементов. Может быть, я пойду написать стихотворение об этом сейчас.
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элемент, и следующий элемент будет начинаться с новой строки.
arvil
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
проблема здесь в том, что 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>, но я использую его с соседними <div>.

Андрей
источник
2
Div-ширина 100% - первое решение, данное в принятом ответе.
Тайлер
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и сделать эти новые флексбоксы div 2-го уровня. Это работает для строк. Замените деления с пролетами при использовании режима столбца.
jiggunjer