Flex-Box Box-Sizing: Border-Box Not Working

Flex items not respecting margins and box-sizing: border-box

Keep in mind that box-sizing: border-box brings padding and borders into the width / height calculation, but not margins. Margins are always calculated separately.

The box-sizing property takes two values:

  • content-box
  • border-box

It does not offer padding-box or margin-box.

Consider those terms when referring to the CSS Box Model.

Sample Image

source: W3C

3.1. Changing the Box Model: the box-sizing
property

content-box

The specified width and height apply to the width and height respectively
of the content box of the element. The padding and border of the
element are laid out and drawn outside the specified width and height.

border-box

Length and percentages values for width and height on this element
determine the border box of the element. That is, any padding or
border specified on the element is laid out and drawn inside this
specified width and height. The content width and height are
calculated by subtracting the border and padding widths of the
respective sides from the specified width and height properties.


Also, an initial setting of a flex container is flex-shrink: 1. This means that flex items can shrink in order to fit within the container.

Therefore, a specified width, height or flex-basis will not hold, unless flex-shrink is disabled.

You can override the default with flex-shrink: 0.

Here's a more complete explanation: What are the differences between flex-basis and width?


Here's a simple solution:

You have four boxes. You want three on row 1 and the last on row 2.

This is what you have:

flex: 1 1 33.33%;
margin: 10px;

This breaks down to:

  • flex-grow: 1
  • flex-shrink: 1
  • flex-basis: 33.33%

We know that box-sizing: border-box factors padding and borders into the flex-basis. That's not a problem. But what about the margins?

Well, since you have flex-grow: 1 on each item, there is no need for flex-basis to be 33.33%.

Since flex-grow will consume any free space on the row, flex-basis only needs to be large enough to enforce a wrap.

Since margins also consume free space, flex-grow will not intrude into the margin space.

So try this instead:

flex: 1 1 26%;
margin: 10px;

* {  box-sizing: border-box;}
.horizontal-layout { display: flex; width: 400px;}
header > span { flex: 1 0 26%; /* ADJUSTED */ margin: 10px;}
header#with-border-padding { flex-wrap: wrap;}
header#with-border-padding>span { flex: 1 0 26%; /* ADJUSTED */}
header#with-border-padding>.button { border: 1px solid black; padding-left: 5px;}
header>.button { background-color: grey;}
header>.app-name { background-color: orange;}
NO flex-wrap: wrap, so it not respects the flex 33% <br/><header class="horizontal-layout">  <span class="button">A</span>  <span class="app-name">B</span>  <span class="button">C</span>  <span class="button">D</span></header><br/><br/> WITH flex-wrap: wrap : I expect to have 3 boxes in first row and D box in a down<br/><header id="with-border-padding" class="horizontal-layout">  <span class="button">A</span>  <span class="app-name">B</span>  <span class="button">C</span>  <span class="button">D</span></header>

flex-box box-sizing: border-box not working

you could use :not:

.cnr>div{
box-sizing: border-box;
overflow: hidden;
}

.cnr>div:not(.closed) {
border: 1em solid;
padding: 1em;
}

$('.cnr').on('click', function(){  $(this).find('div').toggleClass('closed');})
.cnr {  display: flex;  height: 100%;  background-color: grey;  position: absolute;  border: 1px red solid;}
.cnr>div{ box-sizing: border-box; overflow: hidden;}
.cnr>div:not(.closed) { border: 1em solid; padding: 1em;}
.cnr>.closed { width: 0; flex-basis: 0; flex-shrink: 1; flex-grow: 0; min-width: 0; min-height: 0; overflow: hidden;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div class="cnr">  <div>    open  </div>  <div class="closed">    closed  </div></div>

Flex items wrapping even with box-sizing border-box

Keep in mind that box-sizing: border-box brings padding and borders into the width / height calculation, but not margins. Margins are always calculated separately.

The box-sizing property takes two values:

  • content-box
  • border-box

It does not offer padding-box or margin-box.

Consider those terms when referring to the CSS Box Model.

Sample Image

source: W3C

So when you set your item widths to 33.3% and add 10px margins on the right and left, an overflow condition is triggered, resulting in a wrap of the third item.

33.3% + 33.3% + 33.3% + 10px + 10px + 10px + 10px + 10px + 10px > 100%

Instead, try this on the items:

flex: 1 0 26%

This shorthand rule breaks down to this:

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

With flex-grow: 1 there's no need for flex-basis to be 33.3%.

Since flex-grow will consume free space in the row, flex-basis only needs to be large enough to enforce a wrap.

In this case, with flex-basis: 26%, a maximum of three items can exist on the line, there's plenty of space left for margins, and flex-grow fills any gaps.

.wrapper {  display: flex;  flex-wrap: wrap;}
.child__wrapper { flex: 1 0 26%; margin: 10px; height: 300px; box-sizing: border-box; background: rebeccapurple;}
* { box-sizing: border-box; margin: 0; padding: 0;}
<div class="wrapper">  <div class="child__wrapper">1</div>  <div class="child__wrapper">2</div>  <div class="child__wrapper">3</div>  <div class="child__wrapper">4</div>  <div class="child__wrapper">5</div>  <div class="child__wrapper">6</div>  <div class="child__wrapper">7</div>  <div class="child__wrapper">8</div>  <div class="child__wrapper">9</div></div>

CSS position absolute and full width problem

You could set both left and right property to 0. This will make the div stretch to the document width, but requires that no parent element is positioned (which is not the case, seeing as #header is position: relative;)

#site_nav_global_primary {    
position: absolute;
top: 0;
left: 0;
right: 0;
}

Demo at: http://jsfiddle.net/xWnq2/, where I removed position:relative; from #header

Flex-grow doesn't respect border-box. Bug or not? And any way to overcome?

This is not a bug. It is the desired behavior.

When you have a bunch of flex-children, and apply flex-basis: 0 and flex-grow: 1 to them, the following steps are being taken by the browser:

  • Render text and other content the flex-children have
  • Apply padding, borders and margins (taking the box-sizing into account)
  • Starting with the smallest flex-child (because of flex-basis: 0) keep adding width to the items until the container is full (flex-grow: 1).

That last step is where your problem lies. The browser doesn't force the elements to first be 0 pixels wide and all grow evenly. The browser simply starts with the smallest flex-child, giving it more width until it has grown as wide as the second smallest. At that point both of these flex-children will both grow evenly. And so forth, adding width until all space is distributed. This is also why box-sizing: border-box seems to not working.

You can fix this by adding a container to each of the flex-items, which has the border-box part applied. See this Fiddle. The contents have been wrapped into another div, and the styles have been applied to it as well (except for the flex-specific properties, of course).



Related Topics



Leave a reply



Submit