Chet
Chet

Reputation: 19889

How to make Flexbox items the same size

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

Upvotes: 575

Views: 787226

Answers (14)

Daniel Silva
Daniel Silva

Reputation: 343

const styles = StyleSheet.create({
  itemsWrapper: {
    display: 'flex',
    flex: 1,
    flexDirection: 'row',
    gap: 4,
    justifyContent: 'space-between',
  },
  item: {
    display: 'flex',
    flex: 1,
  },
})

By adding item to 2 or more containers, you will have it at the same width as your primary axis is X (for the flexDirection: 'row')

Hope this helps!

Upvotes: -1

AmerllicA
AmerllicA

Reputation: 32572

React Natve FlexBox

To have the same sizes for the children on a React Native project do the following:

const styles = StyleSheet.create({
  itemsWrapper: {
    flexDirection: 'row',
    gap: 4,
    justifyContent: 'space-between',
  },
  item: {
    flexGrow: 1,
    flexShrink: 1,
    flexBasis: 0,
  },
})

Upvotes: -1

Tobias Cohen
Tobias Cohen

Reputation: 19999

It can be very difficult to reliably distribute columns evenly with flexbox for complicated reasons involving padding, border and margin which this article explains in detail.

One alternative suggested there is to instead use a grid with these styles:

.grid-container {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}

Upvotes: 1

Diya7
Diya7

Reputation: 1

.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!

Upvotes: -1

Adam Jenkins
Adam Jenkins

Reputation: 55792

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;

Upvotes: 809

Steve
Steve

Reputation: 5005

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%',

Upvotes: 11

solepixel
solepixel

Reputation: 807

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>

Upvotes: 7

Hyzyr
Hyzyr

Reputation: 937

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));
}

Upvotes: 1

Mr.Bil
Mr.Bil

Reputation: 43

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 %.

Upvotes: 4

technosis
technosis

Reputation: 87

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.

Upvotes: 0

Brett Donald
Brett Donald

Reputation: 14340

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>

Upvotes: 46

Jason Song
Jason Song

Reputation: 2670

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.

Upvotes: 238

Andrew
Andrew

Reputation: 1

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.

Upvotes: 5

Josh Crozier
Josh Crozier

Reputation: 241188

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;
}

Upvotes: 157

Related Questions