Reputation: 4007
I'm curious if this layout is possible with flexbox. I can't seem to work out divs 3 & 4 to fall under #2. This is pretty easy with floats, just curious if I'm missing some properties that may help with flexbox.
Layout
+-------+-------+-------+
| div 1 | div 2 |
+ +-------+-------+
| | div 3 | div 4 |
+-------+-------+-------+
Markup
<div class="features">
<div class="feature feature-1">1</div>
<div class="feature feature-2">2</div>
<div class="feature feature-3">3</div>
<div class="feature feature-4">4</div>
</div>
Demo
http://codepen.io/mikevoermans/pen/xbWvJJ?editors=110
Upvotes: 6
Views: 5732
Reputation: 44043
It's very possible and easy with flexbox to achieve the layout by employing three flex containers.
#rFlex
wraps everything into a row.#cFlex
causing #flex2, #flex3
, and #flex4
to flow in a column.#flex3
and #flex4
are set to flow horizontally by #sFlex
.#cflex
is inline-flex
so that it can stay solidly next to #flex1
html {
box-sizing: border-box;
font: 400 16px/1.45'Source Code Pro';
}
*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
border: 0;
outline: none;
}
body {
background: #121;
color: #FEF;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
position: relative;
width: 100vw;
height: 100vh;
}
/* Flex Containers */
#rFlex {
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row wrap;
flex-flow: row wrap;
-webkit-justify-content: center;
justify-content: center;
width: -moz-fit-content;
width: -webkit-fit-content;
width: fit-content;
height: auto;
}
#cflex {
display: -webkit-inline-flex;
display: inline-flex;
-webkit-flex-flow: column wrap;
flex-flow: column wrap;
-webkit-justify-content: flex-start;
justify-content: flex-start;
-webkit-align-items: center;
align-items: center;
height: 80vh;
width: 45vw;
}
#sFlex {
display: -webkit-inline-flex;
display: inline-flex;
-webkit-flex-flow: row nowrap;
flex-flow: row nowrap;
-webkit-justify-content: center;
justify-content: center;
}
/* Flex Items */
.flex {
-webkit-flex: 0 0 auto;
flex: 0 0 auto;
}
#flex1 {
width: 45vw;
height: 80vh;
background: red;
}
#flex2 {
width: 45vw;
height: 40vh;
background: blue;
}
#flex3,
#flex4 {
width: 22.5vw;
height: 40vh;
}
#flex3 {
background: yellow;
}
#flex4 {
background: green;
}
<main id="rFlex">
<section id="flex1" class="flex">
</section>
<article id="cFlex">
<section id="flex2" class="flex">
</section>
<aside id="sFlex">
<section id="flex3" class="flex">
</section>
<section id="flex4" class="flex">
</section>
</aside>
</article>
</main>
Upvotes: 0
Reputation: 33442
Not possible with flexbox, but possible with CSS Grid. It's not yet shipped with all major browsers, but there's a polyfill:
https://jsfiddle.net/hvdq63ah/
.features {
display: grid;
grid-template-areas:
"feature1 feature2 feature2"
"feature1 feature3 feature4";
grid-template-columns: auto minmax(min-content, 1fr) minmax(min-content, 1fr);
grid-template-rows: auto minmax(min-content, 1fr);
background-color: #fff;
}
.feature-1 { grid-area: feature1 }
.feature-2 { grid-area: feature2 }
.feature-3 { grid-area: feature3 }
.feature-4 { grid-area: feature4 }
.feature {
border: 1px solid black;
padding: 20px;
}
<div class="features">
<div class="feature feature-1">1</div>
<div class="feature feature-2">2</div>
<div class="feature feature-3">3</div>
<div class="feature feature-4">4</div>
</div>
Upvotes: 1
Reputation: 288520
Flexbox does not like flex items that expand through multiple columns or rows, because in fact flexbox has no grid notion.
However, using some tricks, you can achieve this layout (and more complicated ones too):
Use a row layout
┌─┬─┬─┬─┐
│1│2│3│4│
└─┴─┴─┴─┘
Allow line breaks with flex-wrap: wrap
.
Use a pseudo element to force a line break after 2
┌─┬─┐
│1│2│
├─┼─┤
│3│4│
└─┴─┘
Use flex: 1
on all flex items.
┌─────────┬─────────┐
│1 │2 │
├─────────┼─────────┤
│3 │4 │
└─────────┴─────────┘
Set margin-left: 50%
to 3
┌─────────┬─────────┐
│1 │2 │
└─────────┼────┬────┤
│3 │4 │
└────┴────┘
Set height: 200px
, to 2, 3 and 4. Set height: 400px
to 1.
┌─────────┬─────────┐
│1 │2 │
│ ├─────────┘
│ │
└─────────┼────┬────┐
│3 │4 │
└────┴────┘
Set margin-bottom: -200px
to 1:
┌─────────┬─────────┐
│1 │2 │
│ ├────┬────┤
│ │3 │4 │
└─────────┴────┴────┘
Since you have borders, use box-sizing: border-box
on all boxes to make height
include the borders. Otherwise 1 would need height: 416px; margin-bottom: -216px
.
Note flexbox introduces auto
as the new initial value of min-width
. That could allow the content to force some boxes to grow. That would break the layout, so disable it with min-width: 0
or setting overflow
to anything but visible
.
Here is the code:
.features {
display: flex;
flex-flow: row wrap;
}
.feature {
background: #ccc;
border: 8px solid #fff;
height: 200px;
box-sizing: border-box;
min-width: 0;
flex: 1;
}
.feature-1 {
/* Make it taller without increasing the height of the flex line */
height: 400px;
margin-bottom: -200px;
}
.features:after {
/* Force line break */
content: '';
width: 100%;
}
.feature-2 ~ .feature {
/* Place 3 and 4 after the line break */
order: 1;
}
.feature-3 {
margin-left: 50%;
}
<div class="features">
<div class="feature feature-1">1</div>
<div class="feature feature-2">2</div>
<div class="feature feature-3">3</div>
<div class="feature feature-4">4</div>
</div>
However, it would be easier to modify the HTML in order to have nested flexboxes.
#wrapper {
height: 400px;
}
.flex {
display: flex;
}
.column {
flex-direction: column;
}
.flex > div {
min-width: 0;
flex: 1;
}
.item {
background: #ccc;
border: 8px solid #fff;
}
<div id="wrapper" class="flex row">
<div class="item">1</div>
<div class="flex column">
<div class="item">2</div>
<div class="flex row">
<div class="item">3</div>
<div class="item">4</div>
</div>
</div>
</div>
Upvotes: 21