Alex MM
Alex MM

Reputation: 316

flex-basis and box-sizing

According to flex-basis MDN documentation the flex-basis property calculates the size of a flex item related to the content box, unless a different option is defined by the box-sizing CSS property. But I didn't get the desired result neither in current Chrome nor in IE11.

I have written 2 examples:

.horizontal-layout {
  display: flex;
  flex-direction: row;
}
header > span {
  flex: 1 1 100%;
}
header > .button {
  background-color: grey;
}
header > .app-name {
  background-color: orange;
}
header#with-border-padding > span {
  box-sizing: border-box; /* this is not useful at all */
}
header#with-border-padding > .button {
  border: 1px solid black;
  padding-left: 5px;
}
<header class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

<header id="with-border-padding" class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

jsfiddle

So thanks if someone can clarify about second example question. In my code you can easily compare the sizes given to the <span> tags between both examples.

Upvotes: 10

Views: 9700

Answers (1)

Michael Benjamin
Michael Benjamin

Reputation: 371699

So it's clear that the columns across the two rows don't line up:

enter image description here

.horizontal-layout {
  display: flex;
  flex-direction: row;
}

header > span {
  flex: 1 1 100%;
}

header > .button {
  background-color: grey;
}

header > .app-name {
  background-color: orange;
}

header#with-border-padding > span {
  box-sizing: border-box;
}

header#with-border-padding > .button {
  border: 1px solid black;
  padding-left: 5px;
}
<header class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

<header id="with-border-padding" class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

There are several ways to tackle this problem, and they involve flex-basis and box-sizing, and also flex-shrink and padding.

For example, if you disable flex-shrink, the alignment problem is gone.

.horizontal-layout {
  display: flex;
  flex-direction: row;
}

header > span {
  flex: 1 0 100%; /* adjustment */
}

header > .button {
  background-color: grey;
}

header > .app-name {
  background-color: orange;
}

header#with-border-padding > span {
  box-sizing: border-box;
}

header#with-border-padding > .button {
  border: 1px solid black;
  padding-left: 5px;
}
<header class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

<header id="with-border-padding" class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

Similarly, if you remove the padding, the alignment problem is also fixed.

.horizontal-layout {
  display: flex;
  flex-direction: row;
}

header > span {
  flex: 1 1 100%;
}

header > .button {
  background-color: grey;
}

header > .app-name {
  background-color: orange;
}

header#with-border-padding > span {
  box-sizing: border-box;
}

header#with-border-padding > .button {
  border: 1px solid black;
  /* padding-left: 5px; */  /* adjustment */
}
<header class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

<header id="with-border-padding" class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

The way flex-basis, flex-shrink, padding and border-box interact to establish box sizes involves some relatively complex calculations. They are explained here:

A simple solution to the problem is:

header > span { flex: 1 0 7px; }

.horizontal-layout {
  display: flex;
  flex-direction: row;
}

header > span {
  flex: 1 0 7px; /* adjustment */
}

header > .button {
  background-color: grey;
}

header > .app-name {
  background-color: orange;
}

header#with-border-padding > span {
  box-sizing: border-box;
}

header#with-border-padding > .button {
  border: 1px solid black;
  padding-left: 5px;
}
<header class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

<header id="with-border-padding" class="horizontal-layout">
  <span class="button">A</span>
  <span class="app-name">B</span>
  <span class="button">C</span>
</header>

With flex-grow: 1 defined in the flex shorthand, there's no need for flex-basis to be 100%. Each item will receive an equal share of free space on the line. However, flex-basis needs to be at least big enough to absorb the padding and border coming from box-sizing: border-box (in this case 7px). The columns are now aligned across rows.

Upvotes: 8

Related Questions