27

There is a flexbox grid.

.flex {
  display: flex;
  flex-wrap: wrap;
  border: 2px solid red;
}

.item {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 2px solid blue;
}
<div class="flex">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item new-string"></div>
</div>

How to transfer .new-string to a new line, along with the elements that follow it?

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Yuri
  • 754
  • 3
  • 9
  • 18

4 Answers4

38

If you look at this great answer you'll notice that the only cross-browser way (without 2 line break limit) is inserting 100%-width empty blocks ("line-breaks"). So for similar markup this will look like

.flex {
  display: flex;
  flex-wrap: wrap;
  border: 2px solid red;
}

.item {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 2px solid blue;
}

.line-break {
  width: 100%;
}
<div class="flex">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="line-break"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="line-break"></div>
  <div class="item"></div>
  <div class="line-break"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>

If you want to preserve your markup style, you'll have to insert this line-break blocks via JavaScript:

var items = document.querySelectorAll(".flex > .item.new-string");

for (var i = 0; i < items.length; i++) {
  var lineBreak = document.createElement('div');
  lineBreak.className = "line-break";

  items[i].parentNode.insertBefore(lineBreak, items[i]);
}
.flex {
  display: flex;
  flex-wrap: wrap;
  border: 2px solid red;
}

.item {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 2px solid blue;
}

.line-break {
  width: 100%;
}
<div class="flex">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item"></div>
  <div class="item new-string"></div>
  <div class="item"></div>
  <div class="item new-string"></div>
  <div class="item new-string"></div>
  <div class="item"></div>
  <div class="item"></div>
</div>
Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
5

This seems to be possible to do with Grid-layout. First to position items inline you can use

grid-template-columns: repeat(auto-fill, 50px);

so that each item takes 50px and it will position items in one line until no more items can fit in one line. And then you can use grid-column-start: 1; on specific item so that it goes to new line.

* {
  box-sizing: border-box;
}
.flex {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, 50px);
  border: 2px solid red;
}

.item {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 2px solid blue;
}

.new-string {
  grid-column-start: 1;
  background: red;
}
<div class="flex"><div class="item"></div><div class="item"></div><div class="item"></div><div class="item new-string"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item"></div><div class="item new-string"></div><div class="item"></div><div class="item"></div><div class="item new-string"></div><div class="item"></div></div>
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • If you go with this route, please make sure to check for browser compatibility – Huangism Jul 13 '17 at 17:54
  • Great answer, worth noting that it's impossible to translate this markup to IE/Edge even with outdated markup. In IE/Edge there is no auto-placement, you need to specify row and column for every cell manually (unless they every cell content will stack in single cell) but here we can't do this (due to need to have flexible autogenerated grid). – Vadim Ovchinnikov Jul 13 '17 at 18:06
4

As an alternative you could simply do this

HTML

<div class="flex">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item line-break"></div>
  <div class="item new-string"></div>
</div>

CSS

.line-break {
    width: 100%;
}

The 100% width flex item will give you the line break. Easiest way to get a new line in the flex grid, sure you need an extra div but I don't find it that bad of a way to do it

Huangism
  • 16,278
  • 7
  • 48
  • 74
3

All flex items are set by default to order: 0. This means they will be laid out in the order they appear in the source code.

If you give the last item order: 1, this forces it to be last when additional items are added.

The ::before and ::after pseudo elements on a flex container create new flex items.

So if we add one pseudo element with a large enough width, it will force your last item (set by order) to the next row.

.flex {
  display: flex;
  flex-wrap: wrap;
  border: 2px solid red;
}

.item {
  width: 50px;
  height: 50px;
  margin: 5px;
  border: 2px solid blue;
}

.new-string {
  order: 1;
}

.flex::after {
  content: "";
  flex: 0 0 100%;
  height: 0;
}
<div class="flex">
  <div class="item"></div>
  <div class="item"></div>
  <div class="item new-string"></div>
</div>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701