Harry
Harry

Reputation: 54959

Flexbox columns to have boxes that are half the size of the other ones

I have 4 to 8 columns in a row, and I don't know their size. I want 2 of the columns to be half the width as the other ones without knowing how many columns there are in total. How would I do this with flexbox? Thanks.

So i.e. 5 columns should be

[ 1   12.5% ] [ 2   12.5% ] [ 3   25% ] [ 4   25% ] [ 4   25% ]

Upvotes: 1

Views: 3162

Answers (2)

Asons
Asons

Reputation: 87201

Here is 2 ways to do this with Flexbox, where one either use flex-grow or flex-basis.

With flex-grow one simply set the first 2 elements to 1, which mean they will take equal size of the remaining space, and then set 2 for the 3-8 elements, which means they should take twice the size of the first 2.

The downside with this is that the remaining space is based on what's left of the space after what the content in each element consume.

This can be seen in the first 2 rows (lightblue).


If a more exact size is required, flex-basis can do that, and here combined with an adjusted verstion of the can-css-detect-the-number-of-children-an-element-has trick.

The beauty with this is, you can make them behave different based on how many there are.

Fiddle demo

/*  using flex-grow  */
.test1 .flexparent div:nth-child(1),
.test1 .flexparent div:nth-child(2) {
  flex-grow: 1;
  background: #aaf;
}
.test1 .flexparent div:nth-child(n+3) {
  flex-grow: 2;
}

/*  using flex-basis  */
/* four items, first 2 */
.test2 .flexparent div:first-child:nth-last-child(4),
.test2 .flexparent div:first-child:nth-last-child(4) + div {
  flex-basis: calc(100% / 3 / 2);
  background: #0c0;
}
/* four items, last 2 */
.test2 .flexparent div:first-child:nth-last-child(4)  + div ~ div {
  flex-basis: calc(100% / 3);
}
/* five items, first 2 */
.test2 .flexparent div:first-child:nth-last-child(5),
.test2 .flexparent div:first-child:nth-last-child(5) + div {
  flex-basis: calc(100% / 4 / 2);
  background: #0b0;
}
/* five items, last 3 */
.test2 .flexparent div:first-child:nth-last-child(5)  + div ~ div {
  flex-basis: calc(100% / 4);
}
/* six items, first 2 */
.test2 .flexparent div:first-child:nth-last-child(6),
.test2 .flexparent div:first-child:nth-last-child(6) + div {
  flex-basis: calc(100% / 5 / 2);
  background: #0a0;
}
/* six items, last 4 */
.test2 .flexparent div:first-child:nth-last-child(6)  + div ~ div {
  flex-basis: calc(100% / 5);
}
/* seven items, first 2 */
.test2 .flexparent div:first-child:nth-last-child(7),
.test2 .flexparent div:first-child:nth-last-child(7) + div {
  flex-basis: calc(100% / 6 / 2);
  background: #090;
}
/* seven items, last 5 */
.test2 .flexparent div:first-child:nth-last-child(7)  + div ~ div {
  flex-basis: calc(100% / 6);
}
/* eight items, first 2 */
.test2 .flexparent div:first-child:nth-last-child(8),
.test2 .flexparent div:first-child:nth-last-child(8) + div {
  flex-basis: calc(100% / 7 / 2);
  background: #080;
}
/* eight items, last 6 */
.test2 .flexparent div:first-child:nth-last-child(8)  + div ~ div {
  flex-basis: calc(100% / 7);
}

/* general styles */
.flexparent {
  display: flex;
}
.flexparent.nr2, .test2 {
  margin-top: 4px;
}
.flexparent div {
  min-width: 0;                     /*  allow a flex item to shrink below its content  */
  margin: 0 2px;
  text-align: center;
  background: lightblue;
}
.test2 .flexparent div {
  background: lightgreen;
}
.flexparent div {
  padding: 2px 0;
}
.flexparent div:empty {
  padding: 10px 0;
}
<div class="test1">
 <div class="flexparent">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
 </div>
 <div class="flexparent nr2">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
 </div>
</div>
<div class="test2">
 <div class="flexparent">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
 </div>
 <div class="flexparent nr2">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
  <div>8</div>
 </div>
 <div class="flexparent nr2">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
 </div>
 <div class="flexparent nr2">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
 </div>
 <div class="flexparent nr2">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
 </div>
 <div class="flexparent nr2">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
 </div>
</div>


In addition to YD1m's answer, one doesn't need to wrap the 2 first elements, simply set their flex-basis, where the first 2 gets 50% and the rest 100%.

This works like so, as the sum of their set flex-basis is wider than their parent, they will not fit, and because flex-shrink defaults to 1 they will shrink equally. (and since there is no space left, flex-grow doesn't have any effect)

Fiddle demo

Upvotes: 2

YD1m
YD1m

Reputation: 5895

You can wrap the first two columns in a container container which is equal to the width of the other columns.

[[ x / 2 ] [ x / 2 ]] [         x         ] [         x         ]
          x

.main {
  display: flex;
  width: 100%;
  align-content: stretch;
  text-align: center;
}

.main > div {  
  flex: 1 1 100%;        
}

.main > div:not(.wrapper) {
  background: gray;
  margin: 0 2px;
}

.wrapper {
  display: flex;
}

.wrapper .half {  
  background: red;  
  flex: 1 1 50%;  
  margin: 0 2px;
}
<div class="main">
    <div class="wrapper">
        <div class="half">1</div>
        <div class="half">2</div>
    </div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
</div>

Upvotes: 1

Related Questions