mikevoermans
mikevoermans

Reputation: 4007

Layout possible? Flexbox vs Float layout with multiple columns and rows

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

Answers (3)

zer00ne
zer00ne

Reputation: 44043

It's very possible and easy with flexbox to achieve the layout by employing three flex containers.

  1. The main flex container #rFlex wraps everything into a row.
  2. The vertical right is wrapped in #cFlex causing #flex2, #flex3, and #flex4 to flow in a column.
  3. Then the flex items #flex3 and #flex4 are set to flow horizontally by #sFlex.
  4. #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

Vanuan
Vanuan

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

Oriol
Oriol

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

Related Questions