4

I'm using flex for layout purposes, but the browser does not spread the width equally between items.

.parent {
  display: flex;
  width: 200px;
}

.btn1 {
  flex: 1 1 auto;
}
<div class="parent">
  <div class="btn1">
    <button align="left" style="width:100%">Ok</button>
  </div>
  <button align="left" class="btn1">Cancel</button>
  <div>

Now, I want the buttons to split the container length 50% / 50%.

But that's not what's happening. I tried using flex: 1 1 auto and flex: 1 1 0 but with no success.

I know that I can use the OK button directly and it will solve my problem, but in my particular scenario it's important to wrap it with a div.

Now, as I understand it, flex should be able to spread the width equally and that's my goal here.

One more thing though, I noticed that the button content seems to have an effect on the width and I want to ignore this effect somehow.

Thanks!

JSFiddle example: https://jsfiddle.net/edismutko/cvytLkyp/3/

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Edi Smutko
  • 83
  • 1
  • 7

1 Answers1

5

flex-basis: auto vs flex-basis: 0

You're sizing your flex items with flex: 1 1 auto.

However, if you want to distribute space evenly among items, you need to use flex: 1 1 0.

The difference is the flex-basis component.

With flex-basis: 0, every item is considered to have a zero width and flex-grow distributes container space equally among them. This results in all items having the same length.

With flex-basis: auto, the size of the item is factored into the flex-grow calculation and container space is distributed proportionally among items.

So when you want equal length items use flex: 1 1 0, which is the same as flex: 1.

Here's a more detailed explanation: Make flex-grow expand items based on their original size


Default rules on button elements

Browsers apply styles to elements by default. For instance, Chrome adds padding and border widths to button elements.

enter image description here

Reset those defaults.

Now you have two equal width flex items. (Additional styling is up to you.)

.parent {
  display: flex;
  width: 200px;
}

.btn1 {
  flex: 1;
}

button {
  padding: 1px 0;
  border-left-width: 0;
  border-right-width: 0;
}
<div class="parent">
  <div class="btn1">
    <button align="left" style="width:100%">Ok</button>
  </div>
  <button align="left" class="btn1">Cancel</button>
  <div>

box-sizing: border-box

Something else to consider is including the padding and border lengths in the width / flex-basis calculation. Why are borders causing div to overflow container?

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Everything you just mentioned, I already tried and understood.But my issue is that I'm maintaining an infrastructure that was built on the assumption that flex can spread controls equally in a div container, without having to deal with padding and borders and margins.More to the point, I'm looking for a way to divide space equally with flex between any control without having to worry about any padding or border it might have by design. – Edi Smutko Jun 15 '17 at 08:13
  • Look into the CSS *box-sizing* property. In particular, *box-sizing: border-box*. https://stackoverflow.com/a/39585516/3597276 – Michael Benjamin Jun 15 '17 at 10:30
  • i'v used this method but it did not effect the layout at all, same problem still exists, you can try & see for yourself on the JSFiddle example i dave in the question [https://jsfiddle.net/edismutko/cvytLkyp/3/] – Edi Smutko Jun 16 '17 at 07:37
  • The reason the code in your jsfiddle doesn't work is explained in my answer (and the link references). My answer is based on that demo and works to resolve the problem. – Michael Benjamin Jun 16 '17 at 20:14
  • 1
    Thanks, after reading and understanding the material, it seems that the flex calculation takes the padding and border when calculating the width of the controls, in my case I've wrapped the button with a div so there was no padding or border for the calculation, what I had to do is to set the flex-basis: 14px because the contained button has 6 padding for each side and 1px border for each side (all in all 14px), this will make both controls get the same size. – Edi Smutko Jun 18 '17 at 13:29
  • Here is an example in this fiddle I've made: https://jsfiddle.net/aec821fL/ – Edi Smutko Jun 18 '17 at 15:11