Undistraction
Undistraction

Reputation: 43402

Why is flex-basis being ignored?

In the following situation, why is the height of <header> reduced? As far as I can see, <header> should retain the height declared in by flex-basis and <div class="content-wrapper"> should take up the remaining space. This does work until it contains content that is taller than the space available to it. In this situation, <header> partially collapses.

 main {
   position: absolute;
   top: 0;
   bottom: 0;
   left: 0;
   right: 0;
   display: flex;
   flex-direction: column;
 }
 header {
   flex-basis: 50px;
   background: red;
 }
 .content-wrapper {
   background: blue;
   flex: 2;
   overflow-y: auto;
 }
 .content {
   height: 1000px;
   background: green;
 }
<main>
  <header></header>
  <div class="content-wrapper">
    <div class="content"></div>
  </div>
</main>

If you run the snippet full-screen and change the height, the header height changes relative to the screen-height. I would expect it to remain fixed at 50px.

Upvotes: 6

Views: 3461

Answers (2)

Neek
Neek

Reputation: 7489

Apologies for necro posting but Google led me here for my issue of flex-basis being ignored, it was for a different reasons than the OP but this might help someone out there. I was trying to make images arrange side by side with equal size but some unwrappable text forced one box to be larger than the flex-basis I set, causing the layout to break.

In my case the fix was to add overflow-wrap: anywhere so the text became wrappable, and the layout engine could force the flex item to be 25% of the parent's width.

.container {
  max-width: 20em;
  margin: 1em auto;
  border: 2px solid black;
  display: flex;
  flex-wrap: wrap;
}
.item {
  flex: 1 1 25%;
  display: block;
  height: 4em;
  margin: 0;
  /* This will fix the 25% width problem: overflow-wrap: anywhere; */
}

.item.a { background-color: red; }
.item.b { background-color: green; }
.item.c { background-color: blue; }
.item.d { background-color: goldenrod; }
<div class="container">
  <div class="item a">
    <span>One fish two fish red fish blue fish.</span>
  </div>
  <div class="item b">
    <span>One fish two fish red fish blue fish.</span>
  </div>
  <div class="item c">
    <span>One fish twofishredfishblue fish.</span>
  </div>
  <div class="item d">
    <span>One fish two fish red fish blue fish.</span>
  </div>
</div>

<p>The 4 children have been told to be 25% the width of the flex container, but are not because one has unwrappable text content causing it to lay out too wide.</p>
<p>Uncommenting the overflow-wrap style to set it to 'anywhere' will allow that item to wrap its contents and obey the 25% rule.</p>

I was actually layout out figure elements with a figcaption and a gap rule in between the items, which means the simple flex-basis: 25% doesn't work, so for bonus points here's use of calc() to set the flex-basis of each item, though admittedly it's a bit of a hack because it involves knowing the number of children and the gap size.

.container {
  max-width: 20em;
  margin: 1em auto;
  border: 2px solid black;
  display: flex;
  flex-wrap: wrap;
  gap: 10px; /* see flex-basis later */
}
.item {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: calc(25% - 3 * 10px);
  display: block;
  margin: 0;
  overflow-wrap: anywhere;
}

.item.a { background-color: red; }
.item.b { background-color: green; }
.item.c { background-color: blue; }
.item.d { background-color: goldenrod; }
<div class="container">
  <div class="item a">
    <span>One fish two fish red fish blue fish.</span>
  </div>
  <div class="item b">
    <span>One fish two fish red fish blue fish.</span>
  </div>
  <div class="item c">
    <span>One fish twofishredfishblue fish.</span>
  </div>
  <div class="item d">
    <span>One fish two fish red fish blue fish.</span>
  </div>
</div>

<p>Since we know there are 3 gaps of 10px each, we can set the flex-basis to be `calc(25% - 3 * 10px)` which makes each item a little less than 25% the width of the parent to fit all 4 on one row nicely without wrapping.</p>

Upvotes: 0

Sphinxxx
Sphinxxx

Reputation: 13037

@Eric Martinez' comment is correct. To keep elements from shrinking, set flex-shrink to 0 instead.
https://css-tricks.com/snippets/css/a-guide-to-flexbox/

 main {
   position: absolute;
   top: 0;
   bottom: 0;
   left: 0;
   right: 0;
   display: flex;
   flex-direction: column;
 }
 header {
   height: 50px;
   flex-shrink: 0;
   background: red;
 }
 .content-wrapper {
   background: blue;
   flex: 2;
   overflow-y: auto;
 }
 .content {
   height: 1000px;
   background: green;
 }
<main>
  <header></header>
  <div class="content-wrapper">
    <div class="content"></div>
  </div>
</main>

Upvotes: 7

Related Questions