skip to Main Content

I’m not so much looking for a solution as I am trying to understand what is happening.

In the code below, I have a flex enabled div with two child elements.

  • I explicitly set its width of the first child to 18rem.
  • I set the width of the second child to 100%.
.flex {
  display: flex;
}

.w-72 {
  width: 18rem;
}

.w-full {
  width: 100%;
}

.bg-blue-300 {
  --tw-bg-opacity: 1;
  background-color: rgb(147 197 253 / var(--tw-bg-opacity));
}

.bg-orange-200 {
  --tw-bg-opacity: 1;
  background-color: rgb(254 215 170 / var(--tw-bg-opacity));
}
<div class="flex">
  <nav class="bg-blue-300 w-72">Nav</nav>
  <article class="w-full bg-orange-200">Article</article>
</div>

enter image description here

I thought this would expand the <article> to fill the remaining horizontal width, but it actually causes the width of the neighboring <nav> to shrink. (Try running this code with and without w-full to see for yourself.)

Why does this happen?

3

Answers


  1. This is because flex always compromises widths when there are conflicts. It cannot both make the right side 100% and the left side 18rem so it cuts the same amount out of both to make them both fit. For example, if you were to have two items in a flex box, and each one is set to width: 60%, the working width of each item will be 50%, because flex will shave 10% off each side to make them both fit. To fix this, you can specify a min-width which is much more powerful than width by itself.

    However, the correct way to have an item fill the remaining space in a flexbox is to use flex: 1 instead of using width, as shown below.

    .flex {
      display: flex;
    }
    
    .w-72 {
      width: 18rem;
    }
    
    .w-full {
      flex: 1 0 auto;
    }
    
    .bg-blue-300 {
      --tw-bg-opacity: 1;
      background-color: rgb(147 197 253 / var(--tw-bg-opacity));
    }
    
    .bg-orange-200 {
      --tw-bg-opacity: 1;
      background-color: rgb(254 215 170 / var(--tw-bg-opacity));
    }
    <div class="flex">
      <nav class="bg-blue-300 w-72">Nav</nav>
      <article class="w-full bg-orange-200">Article</article>
    </div>
    Login or Signup to reply.
  2. A default setting on a flex container is flex-shrink: 1. This means that flex items will automatically shrink to avoid overflowing the container.

    To force flex items to respect their defined lengths, you must disable flex-shrink.

    Add this to your code:

    .w-72 {
      width: 18rem;
      flex-shrink: 0; /* new */
    }
    

    (The equivalent shorthand for the code above would be flex: 0 0 18rem.)

    .flex {
      display: flex;
    }
    
    .w-72 {
      width: 18rem;
      flex-shrink: 0; /* NEW */
    }
    
    .w-full {
      width: 100%;
    }
    
    .bg-blue-300 {
      --tw-bg-opacity: 1;
      background-color: rgb(147 197 253 / var(--tw-bg-opacity));
    }
    
    .bg-orange-200 {
      --tw-bg-opacity: 1;
      background-color: rgb(254 215 170 / var(--tw-bg-opacity));
    }
    <div class="flex">
      <nav class="bg-blue-300 w-72">Nav</nav>
      <article class="w-full bg-orange-200">Article</article>
    </div>
    Login or Signup to reply.
  3. Applying the w-full class to the element causes it to have a width: 100%, while the element has a fixed width of 18rem. Since the total available space is limited, flex distributes the available space proportionally, causing both elements to shrink so they fit within the container.

    Using flex: 1 is the correct way to make an item fill the remaining space in a flex container, allow it to grow and occupy the available space proportionally, and not have an effect on the width of other elements.

    This should work:

    .flex {
      display: flex;
    }
    
    .w-72 {
      width: 18rem;
    }
    
    .flex-grow {
      flex: 1;
    }
    
    .bg-blue-300 {
      --tw-bg-opacity: 1;
      background-color: rgb(147 197 253 / var(--tw-bg-opacity));
    }
    
    .bg-orange-200 {
      --tw-bg-opacity: 1;
      background-color: rgb(254 215 170 / var(--tw-bg-opacity));
    }
    
    <div class="flex">
      <nav class="bg-blue-300 w-72">Nav</nav>
      <article class="flex-grow bg-orange-200">Article</article>
    </div>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search