Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Align flex items with different heights in the same container

Tags:

html

css

flexbox

I wonder if it's possible to get flex items horizontally aligned to larger flex items in the same container. Using CSS floats it would be easily accomplished, but I haven't been able to get it done with flex items.

View this JSFiddle for a flexbox example.

View this JSFiddle a float example

Grid layout

<div class="flex-container">
 <div class="large-flex-item">
</div>
<div class="small-flex-item">
 </div>
<div class="small-flex-item">
 </div>
</div>

CSS

 .flex-container {
   display: flex;
   flex-direction: row;
   flex-wrap: wrap;
   align-items: flex-start;
   max-width: 500px;
   margin-right: auto;
   margin-left: auto;
 }

 .small-flex-item {
   flex-basis: 33.333%;
   background: #000;
   padding-top: 30%;
 }

 .large-flex-item {
   flex-basis: 66.667%;
   background: #333;
   padding-top: 60%;
 }
like image 809
Tim Avatar asked Dec 03 '15 15:12

Tim


2 Answers

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│
    └─┴─┴─┘
    
  • Allow line breaks with flex-wrap: wrap.

  • Use a pseudo element to force a line break after 2

    ┌─┬─┐
    │1│2│
    ├─┼─┘
    │3│
    └─┘
    
  • Use width: 33% on 2 and 3, and flex: 1 on 1.

    ┌───────────────┬─────┐
    │1              │2    │
    ├─────┬─────────┴─────┘
    │3    │
    └─────┘
    
  • Set margin-left: auto to 3

    ┌───────────────┬─────┐
    │1              │2    │
    └───────────────┼─────┤
                    │3    │
                    └─────┘
    
  • Choose some length x

  • Set height: x to 2 and 3. Set height: 2*x to 1.

    ┌───────────────┬─────┐
    │1              │2    │
    │               ├─────┘
    │               │
    └───────────────┼─────┐
                    │3    │
                    └─────┘
    
  • Set margin-bottom: -x to 1:

    ┌───────────────┬─────┐
    │1              │2    │
    │               ├─────┤
    │               │3    │
    └───────────────┴─────┘
    
  • 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:

.flex-container {
  display: flex;
  flex-flow: row wrap;
}
.flex-item {
  overflow: hidden;
}
.flex-container::after {
  content: '';
  width: 100%; /* Force line break */
}
.large.flex-item {
  flex: 1;
  height: 200px;
  margin-bottom: -100px;
  background: red;
}
.small.flex-item {
  width: 33.333%;
  height: 100px;
  background: green;
}
.small.flex-item + .small.flex-item {
  order: 1;
  margin-left: auto;
  background: blue;
}
<div class="flex-container">
  <div class="large flex-item">1</div>
  <div class="small flex-item">2</div>
  <div class="small flex-item">3</div>
</div>

However, it would be easier to modify the HTML in order to have nested flexboxes.

like image 88
Oriol Avatar answered Sep 29 '22 00:09

Oriol


You can achieve the layout by nesting flex containers.

HTML

<div class="flex-container">

  <div class="large-flex-item"></div><!-- flex item #1 -->

  <div class="flex-container-inner"><!-- flex item #2 & nested flex container -->
     <div class="small-flex-item"></div><!-- this flex item and sibling will align... -->
     <div class="small-flex-item"></div><!-- ... in column next to .large-flex-item -->
  </div>

</div>

CSS

 .flex-container {
   display: flex;
   width: 500px;
   margin-right: auto;
   margin-left: auto;
 }

 .large-flex-item {
   flex-basis: 66.667%;
   height: 200px;
   background: #333;
 }

.flex-container-inner {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.small-flex-item {
   flex-basis: 100%;
   height: 100px;
   background: #000;
 }

DEMO

like image 43
Michael Benjamin Avatar answered Sep 29 '22 00:09

Michael Benjamin