Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to start a new column in flex column wrap layout

Tags:

css

flexbox

I want my data to be arranged in columns (top to bottom, left to right) and every heading inside the data should start a new column. There are three constraints:

  • Must use flex (I need to use a feature specific to flex)
  • Cannot group the data (e.g. wrap all data items inside one div)
  • Cannot set fixed height

My question is how do I force a column break inside a flex-flow: column wrap layout?

.grid {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}
.grid .head {
  width: 25%;
  background: orange;
  border-bottom: thin dotted;
}
.grid .data {
  width: 25%;
  background: yellow;
  border-bottom: thin dotted;
}
/* my attempt to solve this */
.grid {
  height: 76px;
}
<div class="grid">
  <div class="head">Column 1 (3 items)</div>
  <div class="data">item 1-1</div>
  <div class="data">item 1-2</div>
  <div class="data">item 1-3</div>
  <div class="head">Column 2 (4 items)</div>
  <div class="data">item 2-1</div>
  <div class="data">item 2-2</div>
  <div class="data">item 2-3</div>
  <div class="data">item 2-4</div>
  <div class="head">Column 3 (2 items)</div>
  <div class="data">item 3-1</div>
  <div class="data">item 3-2</div>
  <div class="head">Column 4 (1 items)</div>
  <div class="data">item 4-1</div>
</div>
like image 647
Salman A Avatar asked Nov 25 '14 05:11

Salman A


People also ask

How do you wrap a flex column?

If you want to cause them to wrap once they become too wide you must add the flex-wrap property with a value of wrap , or use the shorthand flex-flow with values of row wrap or column wrap . Items will then wrap in the container.

How do you break a flex row?

Using an element to break to a new flex row comes with an interesting effect: we can skip specifying the width of any item in our flex layout and rely completely on the line breaks to define the flow of our grid. This produces a layout with two vertically stacked full-width items (I've added a border to the .

What does the flex-wrap wrap rule do?

The flex-wrap property allows enabling the control direction in which lines are stacked. It is used to designate a single line or multi-line format to flex items inside the flex container.

How do you show 3 items per row in flexbox?

For 3 items per row, add on the flex items: flex-basis: 33.333333% You can also use the flex 's shorthand like the following: flex: 0 0 33.333333% => which also means flex-basis: 33.333333% .


3 Answers

Apparently, the correct solution is to use the break-before or break-after property:

A break is forced wherever the CSS2.1 page-break-before/page-break-after [CSS21] or the CSS3 break-before/break-after [CSS3-BREAK] properties specify a fragmentation break.

At the time of writing, most browsers implement the *-break-* properties incorrectly or do not implement them at all. Consider this answer ahead of its time.

The following demo works in:

  • FF33

.grid {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}
.grid .head {
  width: 25%;
  background: orange;
  border-bottom: thin dotted;
}
.grid .data {
  width: 25%;
  background: yellow;
  border-bottom: thin dotted;
}
/* force column breaks */
.grid .head:nth-child(n + 2) {
  page-break-before: always; /* FF33 */
}
<div class="grid">
  <div class="head">Column 1 (3 items)</div>
  <div class="data">item 1-1</div>
  <div class="data">item 1-2</div>
  <div class="data">item 1-3</div>
  <div class="head">Column 2 (4 items)</div>
  <div class="data">item 2-1</div>
  <div class="data">item 2-2</div>
  <div class="data">item 2-3</div>
  <div class="data">item 2-4</div>
  <div class="head">Column 3 (2 items)</div>
  <div class="data">item 3-1</div>
  <div class="data">item 3-2</div>
  <div class="head">Column 4 (1 items)</div>
  <div class="data">item 4-1</div>
</div>
like image 77
Salman A Avatar answered Oct 24 '22 01:10

Salman A


I don't think there is a way to do this with flexbox, however, if we use column-count we can take advantage of the properties:

‘break-before’, ‘break-after’, ‘break-inside’

In particular:

We can set break-before: column; on each 'head' element, where the column value means:

Always force a column break before the generated box.

(similarly if we were using break-after:column this would force a column break after the generated box )

NB: Browser support is currently limited to IE (!!)

.grid {
    columns: 4;
    column-gap: 0;
}

.grid > div {
  background: lightyellow;
  border-bottom: thin dotted;
}

.grid .head {
  background: gold;
  border-bottom: thin dotted;
  break-before: column; /*  👈 this is the vital rule  */
}

@media screen and (min-width:0\0) { 
    .grid {
        position: relative;
        left:-20vw;
        /* Probably because IE wants to add a column before the first head class?? 
        Interestingly enough though, the following selector does not work:
        .data + .head { break-before: column; } */
   }
}
<div class="grid">
  <div class="head">Column 1 (3 items)</div>
  <div>item 1-1</div>
  <div>item 1-2</div>
  <div>item 1-3</div>
  <div class="head">Column 2 (4 items)</div>
  <div>item 2-1</div>
  <div>item 2-2</div>
  <div>item 2-3</div>
  <div>item 2-4</div>
  <div class="head">Column 3 (2 items)</div>
  <div>item 3-1</div>
  <div>item 3-2</div>
  <div class="head">Column 4 (1 items)</div>
  <div>item 4-1</div>
</div>

--

Note that in the above fiddle for IE there seems to be a positioning issue (bug?) so I placed some code in a special media query that only effects IE so as not to effect other browsers

like image 36
Danield Avatar answered Oct 24 '22 00:10

Danield


If you can dynamically add a div before each head (except the first), it may be possible. Credits go to Tobias Bjerrome Ahlin. Tested on Chrome, Firefox, Safari and IE11.

.container {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  height: 200px;
}

.item {
  background-color: #A2CBFA;
  border: 1px solid #4390E1;
  margin: 2px;
}

.break {
  flex-basis: 100%;
}
<div class="container">
  <div class="item">item 1</div>
  <div class="item">item 2</div>
  <div class="break"></div>
  <div class="item">item 3</div>
  <div class="item">item 4</div>
  <div class="item">item 5</div>
  <div class="break"></div>
  <div class="item">item 6</div>
  <div class="break"></div>
  <div class="item">item 7</div>
  <div class="item">item 8</div>
</div>
like image 3
Moussa Avatar answered Oct 24 '22 00:10

Moussa