At one point I was toying with a CSS spec suggestion for this, but then I figured there is probably already a solution that I am missing. An example of the kind of layout I'm talking about would look something like this:
+-----------+---+
| 1 | 6 |
+---+---+---+ |
| 2 | 3 | 4 +---+
+---+---+---+ 7 |
| 5 | |
+-----------+---+
The problem is those three boxes in the middle of the left column are stacked along the cross axis, and I can't find a mechanism in CSS to do this. I know this could be done with a div wrapped around those 3 items that is a row direction flex layout, but that approach breaks the flexibility of a flex layout because those items can no longer be re-ordered around the outer layout and a column/row break can no longer happen between them. So, how can this be achieved this with only CSS, so that the flex layout stays flexable?
HTML:
<div id="flex-layout">
<div id="item1">1</div>
<div id="item2">2</div>
<div id="item3">3</div>
<div id="item4">4</div>
<div id="item5">5</div>
<div id="item6">6</div>
<div id="item7">7</div>
</div>
CSS:
#flex-layout {
display: flex;
flex-direction: column;
height: 300px;
width: 400px;
flex-wrap: wrap;
align-items: stretch;
}
#item1 {
flex: 0 0 100px;
width: 300px;
}
#item2 {
flex: 0 0 100px;
width: 100px;
}
#item3 {
flex: 0 0 100px;
width: 100px;
}
#item4 {
flex: 0 0 100px;
width: 100px;
}
#item5 {
flex: 0 0 100px;
}
#item6 {
flex: 0 0 150px;
width: 100px;
}
#item7 {
flex: 0 0 150px;
}
Using multiple flex containers would be easier.
But if you want a single container, you can still do it, with those assumptions:
Then, you can
Use a row layout
┌─┬─┬─┬─┬─┬─┬─┐
│1│2│3│4│5│6│7│
└─┴─┴─┴─┴─┴─┴─┘
Reorder the flex items: 1,6,2,3,4,5,7
┌─┬─┬─┬─┬─┬─┬─┐
│1│6│2│3│4│5│7│
└─┴─┴─┴─┴─┴─┴─┘
Allow line breaks with flex-wrap: wrap
.
Use pseudo elements to force a line break before 2 and after 4
┌─┬─┐
│1│6│
├─┼─┼─┐
│2│3│4│
├─┼─┼─┘
│5│7│
└─┴─┘
Use flex-grow: 0
on 6 and 7. Use flex-grow: 1
on the other ones.
┌─────────┬─┐
│ 1 │6│
├───┬───┬─┴─┤
│ 2 │ 3 │ 4 │
├───┴───┴─┬─┤
│ 5 │7│
└─────────┴─┘
Set the desired with, w
, to 6 and 7. Add margin-right: w
to 4
┌─────┬───┐
│ 1 │ 6 │
├─┬─┬─┼───┘
│2│3│4│
├─┴─┴─┼───┐
│ 5 │ 7 │
└─────┴───┘
Set the desired height, h
, to 2, 3 and 4. Add margin-bottom: -h/2
to 6, and margin-top: -h/2
to 7.
┌─────┬───┐
│ 1 │ 6 │
├─┬─┬─┤ │
│2│3│4├───┤
├─┴─┴─┤ 7 │
│ 5 │ │
└─────┴───┘
Additionally, it might be a good idea adding a width
or max-width
to 2,3,4. Otherwise, if their content is wide enough, they will be placed in different lines, breaking the layout.
Here is the code:
#flex-layout {
display: flex; /* Magic begins */
flex-wrap: wrap; /* Multiline */
}
#item1 { order: 1; }
#item6 { order: 2; }
#item2 { order: 3; }
#item3 { order: 4; }
#item4 { order: 5; }
#item5 { order: 6; }
#item7 { order: 7; }
#flex-layout > div {
border: 1px solid;
box-sizing: border-box;
}
#item2, #item3, #item4 {
height: 50px; /* h */
}
#item6 {
margin-bottom: -25px; /* -h/2 */
}
#item7 {
margin-top: -25px; /* -h/2 */
}
#item1, #item2, #item3, #item4, #item5 {
flex-grow: 1;
}
#item6, #item7 {
width: 25%; /* w */
flex-grow: 0;
}
#item4 {
margin-right: 25%; /* w */
}
#flex-layout:before {
/* Force line break before #item2 */
content: '';
width: 100%;
order: 3;
}
#flex-layout:after {
/* Force line break after #item4 */
content: '';
width: 100%;
order: 5;
}
<div id="flex-layout">
<div id="item1">1</div>
<div id="item2">2</div>
<div id="item3">3</div>
<div id="item4">4</div>
<div id="item5">5</div>
<div id="item6">6</div>
<div id="item7">7</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With