482

I want to use Flexbox that has some number of items that are all the same width. I've noticed that Flexbox distributes the space around evenly, rather than the space itself.

For example:

.header {
  display: flex;
}

.item {
  flex-grow: 1;
  text-align: center;
  border: 1px solid black;
}
<div class="header">
  <div class="item">asdfasdfasdfasdfasdfasdf</div>
  <div class="item">z</div>
</div>

The first item is a lot bigger than the second. If I have three items, four items, or n items, I want them all to appear on the same line with an equal amount of space per item.

Any ideas?

http://codepen.io/anon/pen/gbJBqM

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Chet
  • 18,421
  • 15
  • 69
  • 113

11 Answers11

690

Set them so that their flex-basis is 0 (so all elements have the same starting point), and allow them to grow:

flex: 1 1 0px;

Your IDE or linter might mention that the unit of measure 'px' is redundant. If you leave it out (like: flex: 1 1 0), IE will not render this correctly. So the px is required to support Internet Explorer, as mentioned in the comments by @fabb;

moffeltje
  • 4,521
  • 4
  • 33
  • 57
Adam Jenkins
  • 51,445
  • 11
  • 72
  • 100
  • 165
    It should be noted that the `flex` property is a shorthand property for the `flex-grow`, `flex-shrink` and `flex-basis` properties. It's recommended to use the shorthand over the individual properties as the shorthand correctly resets any unspecified components to accommodate common uses. The initial value is `0 1 auto`. – j08691 Mar 12 '18 at 14:36
  • 4
    note that IE11 ignores unitless flex-basis values: https://github.com/philipwalton/flexbugs#flexbug-4 – fabb Aug 02 '19 at 11:27
  • 32
    I had to add `min-width: 0` to achieve using child elements with overflowing text. See https://css-tricks.com/flexbox-truncated-text/ – clemlatz Oct 20 '19 at 10:45
  • This is working fine unless you're not using Safari on iPhone. I came up with the same workaround and I almost got a heart attack after I saw how the site looks on iPhone. p.s. It looks just fine when you make mobile preview on Chrome/Firefox, only iPhone's Safari doesn't understand flex-basis: 0. – Ivica Pesovski Nov 23 '20 at 18:25
  • 11
    I just want to mention that the Internet Explorer (IE) should be ignored. This is an obsolete browser like e.g. Netscape Navigator. The IE was officially replaced by Microsoft Edge. The latest version also runs on Chromium (like Chrome and other modern browsers.) We as web developers should no longer support IE. It is your responsibility to get rid of this crutch. :) Never talk about IE again. – Domske Mar 10 '21 at 11:00
  • 1
    This does not seem to work if some of the items contain padding. Removing the padding makes all the child elements the same size. Any suggestions to avoid removing padding? – redfox05 Mar 19 '21 at 10:18
  • @redfox05 put the padding on an inner element instead of the flex child itself. For example, inside your flex child put a div and gave that wrap all the inner contents, then put the padding you want on the div. – Adam Jenkins Mar 28 '21 at 02:03
  • @Adam, thanks yes, I ended up having to put another wrapper around the child elements, rather than changing the padding on the child elements, as that would have too many other knock on effects elsewhere the component is used. Was hoping Flexbox would in the 'modern options' of putting an end to unnecessary div's but guess not! – redfox05 Mar 29 '21 at 09:12
  • This is a best answer! – giapnh Jun 19 '21 at 11:25
  • Definitely we this best.. if any hint to make any particular column increased compared with others. – Chayan Biswas Jul 02 '21 at 02:35
  • I wrote a sample code here that do the same you want https://codesandbox.io/s/serene-bush-6tqte?file=/index.html – Sahar Ebrahimi Aug 30 '21 at 10:58
  • 1
    You can use `flex: 1` instead of `flex: 1 1 0px` as it means the same thing. See https://developer.mozilla.org/en-US/docs/Web/CSS/flex. – Emanuil Rusev Nov 26 '21 at 14:51
197

You need to add width: 0 to make columns equal if contents of the items make it grow bigger.

.item {
  flex: 1 1 0;
  width: 0;
}

Detail: flex: 1 1 0 is the same as flex-grow: 1; flex-shrink: 1; flex-basis: 0; and if the parent container can not provide enough space for the native-size added together of every item (no space to grow), we need to make the width: 0 to give every item the same start point to grow.

Jason Song
  • 2,224
  • 1
  • 10
  • 7
  • 11
    This appears to be necessary if the contents of `.item` cause it to grow wider than `.item` would naturally be. – Bungle Dec 15 '17 at 21:16
  • 2
    I think you mean `flex: 1 1 0;`, instead of `flex-grow: 1 1 0;` – dǝɥɔS ʇoıןןƎ Nov 26 '18 at 13:40
  • setting the `flex-basis` to `0` serves the same purpose as setting the `width` to `0`. – Stephen Feb 19 '19 at 17:15
  • 1
    In my use case, I was wrapping charts that dynamically adjust to their parent's size and width 0 was necessary for them to work. I am not sure how they were determining the proper width, but flex basis certainly did not work on chrome 72 (released Jan 2019). – Andy Groff Mar 13 '19 at 23:14
  • I think, this reply more satisfying when it fulfilled with text context that don't have any space. – Serhan C. Apr 22 '20 at 13:29
  • 2
    This was the only solution that worked on my situation. Seems that in my case, children was growing bigger than it naturally would, and `flex: 1 1 0` was not having any effect – Danielo515 Jul 13 '20 at 16:16
  • Some of my child elements have padding, and that is messing with the calculations. The `width:0` does not seem to fix this. Any ideas? – redfox05 Mar 19 '21 at 10:15
  • wow today i learned, thank you I also see this necessary in my case where text overflowed – Akin Hwan Mar 22 '23 at 20:35
150

You could add flex-basis: 100% to achieve this.

Updated Example

.header {
  display: flex;
}

.item {
  flex-basis: 100%;
  text-align: center;
  border: 1px solid black;
}

For what it's worth, you could also use flex: 1 for the same results as well.

The shorthand of flex: 1 is the same as flex: 1 1 0, which is equivalent to:

.item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
  text-align: center;
  border: 1px solid black;
}
Håvard Geithus
  • 5,544
  • 7
  • 36
  • 51
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
  • 3
    This is not correct. The default flex value is `flex: 0 1 auto`. Which means setting `flex: 1` will result in `flex: 1 1 auto`. This will not work. The correct answer is `flex: 1 1 0` as stated above by Adam – r.sendecky Jan 29 '17 at 05:47
  • 29
    @r.sendecky No, you are the one who is incorrect. As I stated in my answer, the shorthand of `flex: 1` results in `flex: 1 1 0` **not** `flex: 1 1 auto` like you are claiming. Take a look at the official W3 specification under the ['flex shorthand' section](https://www.w3.org/TR/css-flexbox-1/#flex-property): when `flex-basis` is "omitted from the flex shorthand, its specified value is `0`", not `auto`. Thanks for the random downvote. – Josh Crozier Jan 29 '17 at 16:28
  • 2
    @r.sendecky - Also, take a look at [this example](https://jsfiddle.net/o25wto2d/) I created to visualize the variations. – Josh Crozier Jan 29 '17 at 16:36
  • 1
    Mate, I don't do random down-vote. I test before I write. And I did test it. Your answer does not work - simple as that. I had exactly the same issue not long ago with `flex: 1` and `flex-direction: column`. The children height was not the same when other elements are placed within children. The only thing that fixed it was setting `flex: 1 1 0`. It still stand today with chromium 55.0.2883.87 – r.sendecky Jan 30 '17 at 00:09
  • 6
    @JoshCrozier confirmed that `flex: 1` has the same behavior as `flex: 1 1 0`, and `flex: 0 1 auto` has different behavior. – Ivan Durst Jul 28 '17 at 18:04
  • I had `flex: 1` in my code, but items with more content were still wider, ruining the grid effect. My search landed me here, and adding `flex-grow: 1` fixed the problem. Turns out I need both. – Tom Apr 23 '20 at 16:47
  • When using `whitespace: nowrap` then the item will still grow. – Eric Burel May 11 '20 at 16:08
  • BTW: if want more than 1 row of items, let's say 2 rows of 2 items, you can set flex-basis to 50% (or whatever portion of the parent width you want the items to take up), or a bit smaller if you are using a `gap` setting between them. – clayRay Jul 01 '21 at 04:25
  • 1
    Old but, @JoshCrozier your answer is completely accurate. Thanks – DJ22T Sep 07 '22 at 01:55
41

The accepted answer by Adam (flex: 1 1 0) works perfectly for flexbox containers whose width is either fixed, or determined by an ancestor. Situations where you want the children to fit the container.

However, you may have a situation where you want the container to fit the children, with the children equally sized based on the largest child. You can make a flexbox container fit its children by either:

  • setting position: absolute and not setting width or right, or
  • place it inside a wrapper with display: inline-block

For such flexbox containers, the accepted answer does NOT work, the children are not sized equally. I presume that this is a limitation of flexbox, since it behaves the same in Chrome, Firefox and Safari.

The solution is to use a grid instead of a flexbox.

When you run this snippet, make sure to click on full page to see the effect properly.

body {
  margin: 1em;
}

.wrap-inline-block {
  display: inline-block;
}

#div0, #div1, #div2, #div3, #div4 {
  border: 1px solid #888;
  padding: 0.5em;
  text-align: center;
  white-space: nowrap;
}

#div2, #div4 {
  position: absolute;
  left: 1em;
}

#div0>*, #div1>*, #div2>*, #div3>*, #div4>* {
  margin: 0.5em;
  color: white;
  background-color: navy;
  padding: 0.5em;
}

#div0, #div1, #div2 {
  display: flex;
}

#div0>*, #div1>*, #div2>* {
  flex: 1 1 0;
}

#div0 {
  margin-bottom: 1em;
}

#div2 {
  top: 15.5em;
}

#div3, #div4 {
  display: grid;
  grid-template-columns: repeat(3,1fr);
}

#div4 {
  top: 28.5em;
}
<p>Normal scenario — flexbox where the children adjust to fit the container — and the children are made equal size by setting {flex: 1 1 0}</p>

<div id="div0">
  <div>
    Flexbox
  </div>
  <div>
    Width determined by viewport
  </div>
  <div>
    All child elements are equal size with {flex: 1 1 0}
  </div>
</div>

<p>Now we want to have the container fit the children, but still have the children all equally sized, based on the largest child. We can see that {flex: 1 1 0} has no effect.</p>

<div class="wrap-inline-block">
<div id="div1">
  <div>
    Flexbox
  </div>
  <div>
    Inside inline-block
  </div>
  <div>
    We want all children to be the size of this text
  </div>
</div>
</div>

<div id="div2">
  <div>
    Flexbox
  </div>
  <div>
    Absolutely positioned
  </div>
  <div>
    We want all children to be the size of this text
  </div>
</div>

<br><br><br><br><br><br>
<p>So let's try a grid instead. Aha! That's what we want!</p>

<div class="wrap-inline-block">
<div id="div3">
  <div>
    Grid
  </div>
  <div>
    Inside inline-block
  </div>
  <div>
    We want all children to be the size of this text
  </div>
</div>
</div>

<div id="div4">
  <div>
    Grid
  </div>
  <div>
    Absolutely positioned
  </div>
  <div>
    We want all children to be the size of this text
  </div>
</div>
Brett Donald
  • 6,745
  • 4
  • 23
  • 51
  • Is there a way to get the same effect without hardcoding the number of children in css? – Davorin Sep 17 '20 at 13:20
  • 2
    @Davorin `grid-template-columns: repeat(auto-fill, minmax(100px, auto));` More details at https://css-tricks.com/auto-sizing-columns-css-grid-auto-fill-vs-auto-fit/ – OXiGEN Feb 14 '21 at 14:09
9

I’m not an expert with Flexbox, but I got there by setting the basis to 50% for the two items I was dealing with. Grow to 1 and shrink to 0.

Inline styling: flex: '1 0 50%',

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Steve
  • 4,372
  • 26
  • 37
7

None of these solutions worked for me, but this did:

.header {
  display: flex;
}

.item {
  width: 100%;
}


/* Demo styles, for aesthetics. */

.demo {
  margin: 3rem;
}

.demo .item {
  text-align: center;
  padding: 3rem;
  background-color: #eee;
  margin: 0 1.5rem;
}
<div class="demo">
  <div class="header">
    <div class="item">
      1
    </div>
    <div class="item">
      2
    </div>
    <div class="item">
      3
    </div>
  </div>
</div>

<div class="demo">
  <div class="header">
    <div class="item">
      1
    </div>
    <div class="item">
      2
    </div>
  </div>
</div>

<div class="demo">
  <div class="header">
    <div class="item">
      1
    </div>
    <div class="item">
      2
    </div>
    <div class="item">
      3
    </div>
    <div class="item">
      4
    </div>
    <div class="item">
      5
    </div>
  </div>
</div>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
solepixel
  • 797
  • 2
  • 9
  • 19
5

None of these answers solved my problem, which was that the items weren't the same width in my makeshift flexbox table when it was shrunk to a width too small.

The solution for me was simply to put overflow: hidden; on the flex-grow: 1; cells.

Andrew
  • 5,839
  • 1
  • 51
  • 72
  • Or alternatively, you could use @Josh_Crozier's answer and conditionally set `flex-wrap: wrap;` when the browser window is below a certain width. This will cause the items to wrap and take up 100% of the parent width. – clayRay Jul 01 '21 at 04:41
3

On the child element of flex,

flex: 1 1 25%

this will allow to have four items.

If you want to add more items then you can decrease the %.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mr.Bil
  • 33
  • 5
1

This will work even if you wrapping items, like a Grid, but not so simple you should show where it will wrap in media queries)).

Example:

.flex-item {
    flex: 0 0 calc(25% - (45px / 4))
}

It works like this:

$n: 4; // Number of columns
$gap: 15px; // Margin pixels

.flex-parent {
    display: flex;
    gap: $gap;
}
.flex-item {
    flex: 0 0 calc(100% / $n - (($n - 1) * $gap / $n));
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hyzyr
  • 568
  • 4
  • 13
  • 4 cols) flex: 0 0 calc(25% - (30px / 4 ) ); 3 cols) flex: 0 0 calc(33.3% - (20px / 3) ); 2 cols) flex: 0 0 calc(50% - (10px / 2) ); – Hyzyr Jan 22 '22 at 19:33
0

I was having a similar issue and found a way to cheat.

As others have said, flex-basis and flex-grow: 1 are the way to keep items the same size, but the last row is an exception when there are too few items (they fill all available space, making them larger than the other items). To stop this from happening, I added an empty spacer item with visibility: hidden and set the flex-grow value inline based on a quick calculation of how many items there were.

This is easier if you know the width of the parent container but even if you don't, you can set the flex-grow value on the spacer using media queries and breakpoints.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
technosis
  • 57
  • 1
  • 9
0
.container{
display:flex;
flex-wrap:wrap;
}

.item{
flex basis:(add required width px)
}

If the last row has just one element and it is taking up all the width, then remove 'flex-grow' from flex item and try adding just 'flex-basis:(req px)' or 'flex-shrink:1'. It worked for me!

Diya7
  • 1