Hayley Guillou
Hayley Guillou

Reputation: 3973

Equal width using flex and border-box

I am using box-sizing: border-box; with varying border thicknesses within a flexbox. I want the elements within the flexbox to have equal widths, but it calculates the width of the element without the borders.

Here is an example: the width of my container is 100px, so each element should be 20px; however they are 19.2px (x4) and 23.2px.

.container {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100px;
}

.container .block {
  height: 28px;
  flex: 1;
  border: 1px solid black;
  box-sizing: border-box;
}

.container .block.selected {
  border: 3px solid blue;
}
<div class="container">
  <span class="block">0</span>
  <span class="block">1</span>
  <span class="block selected">2</span>
  <span class="block">3</span>
  <span class="block">4</span>
</div>

Upvotes: 3

Views: 2094

Answers (5)

Michael Benjamin
Michael Benjamin

Reputation: 372059

The flex-grow property does not set the width or height of flex items. It's job is to distribute free space in the container among flex items.

You have all items set to flex: 1, which is shorthand for:

  • flex-grow: 1
  • flex-shrink: 1
  • flex-basis: 0

This distributes free space in the row equally among items.

BUT borders (and padding) are factored in separately.

flex-grow doesn't care about box-sizing: border-box, because box-sizing applies to width and height calculations which, as mentioned earlier, are not functions of flex-grow.

Instead, use the flex-basis property, which is equivalent to width (in a row-direction container) and will respect box-sizing:

flex: 0 0 20%;

.container {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100px;
}

.container .block {
  height: 28px;
  flex: 0 0 20%; /* adjustment */
  border: 1px solid black;
  box-sizing: border-box;
}

.container .block.selected {
  border: 3px solid blue;
}
<div class="container">
  <span class="block">0</span>
  <span class="block">1</span>
  <span class="block selected">2</span>
  <span class="block">3</span>
  <span class="block">4</span>
</div>

Upvotes: 4

dippas
dippas

Reputation: 60573

The box-sizing: border-box is used to change the default CSS box model used to calculate width and height of the elements.

So would be like this:

  • total width = border + padding + content width

    and

  • total height = border + padding + content height

But that doesn't happen in flex-grow, but in flex-basis

Here is a good tutorial about flexbox


So you can use flex:0 20% instead of flex:1,

.container {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100px;
}

.container .block {
  height: 28px;
  flex: 0 20%;
  border: 1px solid black;
  box-sizing: border-box;
}

.container .block.selected {
  border: 3px solid blue;
}
<div class="container">
  <span class="block">0</span>
  <span class="block">1</span>
  <span class="block selected">2</span>
  <span class="block">3</span>
  <span class="block">4</span>
</div>

Note: if you have more elements than 5, then you can use calc() like this flex: 0 calc(100%/8) where 8 is the # of elements you will have

Snippet with more elements

.container {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100px;
}

.container .block {
  height: 28px;
  flex: 0 calc(100%/8);
  border: 1px solid black;
  box-sizing: border-box;
}

.container .block.selected {
  border: 3px solid blue;
}
<div class="container">
  <span class="block">0</span>
  <span class="block">1</span>
  <span class="block selected">2</span>
  <span class="block">3</span>
  <span class="block">4</span>
  <span class="block">5</span>
  <span class="block">6</span>
  <span class="block">7</span>
</div>

Upvotes: 7

Rami.Q
Rami.Q

Reputation: 2476

your problem is here flex: 1; change it to flex: 1 0 20%; even for more/less elements. no need to calculate the width using calc as others mentioned.

also just change this:

.container .block {
  height: 28px;
  flex: 1;
  border: 1px solid black;
  box-sizing:         border-box;
}

to:

.container .block {
  height: 28px;
  flex: 1 0 20%;
  border: 1px solid black;
    -moz-box-sizing:    border-box;
  -webkit-box-sizing: border-box;
    box-sizing:         border-box;
}

DEMO: https://jsfiddle.net/4aww81wv/

Upvotes: 1

Pete
Pete

Reputation: 58462

Instead of setting the flex to one, you can set the flex-basis to 20% and then the width will be divided equally:

.container {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100px;
}

.container .block {
  height: 28px;
  flex-basis: 20%;
  border: 1px solid black;
  box-sizing: border-box;
}

.container .block.selected {
  border: 3px solid blue;
}
<div class="container">
  <span class="block">0</span>
  <span class="block">1</span>
  <span class="block selected">2</span>
  <span class="block">3</span>
  <span class="block">4</span>
</div>

Upvotes: 2

Paolo Forgia
Paolo Forgia

Reputation: 6746

One way could be setting a 2px padding to the .block and removing it for .selected

.container {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100px;
}

.container .block {
  height: 28px;
  flex: 1;
  border: 1px solid black;
  box-sizing: border-box;
  padding: 2px;
}

.container .block.selected {
  border: 3px solid blue;
  padding: 0px;
}
<div class="container">
  <span class="block">0</span>
  <span class="block">1</span>
  <span class="block selected">2</span>
  <span class="block">3</span>
  <span class="block">4</span>
</div>

Upvotes: 1

Related Questions