19

I'm trying to achieve the effect where the boxes labeled "HALF", take up only 50% of the width (aka they share the first row evenly).

The base requirement is that they remain in a single container. Is this possible to achieve using flexbox?

I've tried playing around with flex-grow, flex-shrink, and flex-basis but I'm afraid I'm not understanding how to make it work, or if it's even possible, given the single container requirement.

Consider this fiddle: http://jsfiddle.net/GyXxT/270/

div {
  border: 1px solid;
}

.container {
  width: 400px;
  display: flex;
  flex-direction: column;
}
.child {
  
  height: 200px;
}
.child.half {
  flex: 1 1 10em;
  color: green;
}

.child:not(.half) {

  flex-shrink: 2;
  flex-basis: 50%;
  color: purple; 
}
<div class="container">
  <div class="child half">
    HALF
  </div>
  
  <div class="child half">
    HALF
  </div>
  
   <div class="child">
    FULL
  </div>
   <div class="child">
    FULL
  </div>
  <div class="child">
    FULL
  </div>
   <div class="child">
    FULL
  </div>
</div>
kukkuz
  • 41,512
  • 6
  • 59
  • 95
parliament
  • 21,544
  • 38
  • 148
  • 238

4 Answers4

20

Instead of flex-direction: column, you can try a wrapping flexbox using flex-wrap: wrap; and you can set:

  1. flex-basis: 50% for the half width divs

  2. flex-basis: 100% for the full width divs

See that I have thrown in box-sizing: border-box to adjust for the widths when using flex-basis.

See demo below:

div {
  border: 1px solid;
  box-sizing: border-box;
}
.container {
  width: 400px;
  display: flex;
  flex-wrap: wrap;
}
.child {
  height: 200px;
}
.child.half {
  flex-basis: 50%;
  color: green;
}
.child:not(.half) {
  flex-basis: 100%;
  color: purple;
}
<div class="container">
  <div class="child half">
    HALF
  </div>

  <div class="child half">
    HALF
  </div>

  <div class="child">
    FULL
  </div>
  <div class="child">
    FULL
  </div>
  <div class="child">
    FULL
  </div>
  <div class="child">
    FULL
  </div>
</div>
kukkuz
  • 41,512
  • 6
  • 59
  • 95
  • 1
    There is a much simpler way, although only available for Firefox and Chrome : adding the following properties on the children will limit their size to fit their content : `width: -moz-max-content` and `width: max-content` – ojathelonius Dec 24 '18 at 14:56
7

The flex sizing properties -- flex-grow, flex-shrink, flex-basis and flex -- work only along the main axis of the flex container.

Since your container is flex-direction: column, the main axis is vertical, and these properties are controlling height, not width.

For sizing flex items horizontally in a column-direction container you'll need the width property.

(Here's a more detailed explanation: What are the differences between flex-basis and width?)

To achieve your layout with a single container, see another answer to this question.

If you want to stay in column-direction, you'll need to wrap the .half elements in their own container.

.container {
  display: flex;
  flex-direction: column;
  width: 400px;
}
.container > div:first-child {
  display: flex;
}
.child.half {
  flex: 1 1 10em;
  color: green;
  width: 50%;
}
.child {
  height: 200px;
  width: 100%;
  border: 1px solid;
}
* {
  box-sizing: border-box;
}
<div class="container">
  <div><!-- nested flex container for half elements -->
    <div class="child half">HALF</div>
    <div class="child half">HALF</div>
  </div>
  <div class="child">FULL</div>
  <div class="child">FULL</div>
  <div class="child">FULL</div>
  <div class="child">FULL</div>
</div>
Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
3

The base requirement is that they remain in a single container.

That can also be done without flexbox, by simply float the 2 half elements

div {
  border: 1px solid;
  box-sizing: border-box;
}
.container {
  width: 400px;
}
.child {
  height: 200px;
}
.child.half {
  float: left;
  width: 50%;
  color: green;
}
.child:not(.half) {
  width: 100%;
  color: purple; 
}
<div class="container">
  <div class="child half">
    HALF
  </div> 
  <div class="child half">
    HALF
  </div>
  
   <div class="child">
    FULL
  </div>
   <div class="child">
    FULL
  </div>
  <div class="child">
    FULL
  </div>
   <div class="child">
    FULL
  </div>
</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • While this is true, and something I completely overlooked, the flexbox approach is closer to the desired effect. With 50% widths, when the screen is made smaller, at some point 50% is too small. The flexbox approach simply drops the second item down when it doesnt fit, which is the effect I want. Your approach could be made responsive with media-queries but flexbox suffices for me. Thanks, upvoted – parliament Dec 19 '16 at 19:08
  • @parliament Of course, and thanks ... note, by giving the `half` elements a min-width will do the same ... and combined with a media query, which both solutions need, you can have them all take full with when wrapped – Asons Dec 19 '16 at 19:10
1

If the purpose is to hardcode the size in CSS units, or in percentages (which was mentioned the question), @kukkuz's solution is good as it is.

If you want to size element widths according to their own individual contents, then align-tems: flex-start or similar could do the job. It's possible to deal with the dimension perpendicular to that of the flex layout itself. See a tester on the bottom of the doc page

(Old question, but previous answers were incomplete, some are misleading)

Robert Monfera
  • 1,980
  • 1
  • 22
  • 16