Reputation: 54959
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
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.
/* 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)
Upvotes: 2
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