How to make flexbox items shrink correctly when in a nested container?

前端 未结 1 1875
悲哀的现实
悲哀的现实 2021-01-05 04:37

If I set up a nested flexbox container like so:

<
相关标签:
1条回答
  • 2021-01-05 05:10

    The Problem

    As far as the spec is concerned, this isn't an issue pertaining to flex-basis, width, flex-grow or flex. It's something entirely different.

    4.5. Implied Minimum Size of Flex Items

    To provide a more reasonable default minimum size for flex items, this specification introduces a new auto value as the initial value of the min-width and min-height properties defined in CSS 2.1.

    In other words, a flex item, by default, cannot be smaller than the length of its content (essentially, the longest word or fixed-size element).

    The item cannot stay within its container (or even render a scroll bar or ellipsis), because its content is not permitted to overflow. The content simply expands the item. This behavior applies to fixed-sizing, as well (such as the flex-basis: 400px in your code).

    Again, the initial settings are:

    • min-width: auto, in row-direction
    • min-height: auto, in column-direction

    For a more complete explanation see this post:

    • Why doesn't flex item shrink past content size?

    Solution for Chrome, Safari, Firefox and Edge

    The standard solution to this problem is simple: override the default.

    In your code, add min-width: 0 to .grow1.

    That solves the problem in Chrome, Safari, FF and Edge.

    .container1 {
      margin-top: 10px;
      display: flex;
      width: 200px;
      height: 50px;
      background-color: red;
    }
    
    .grow1 {
      flex-grow: 1;
      height: 40px;
      background-color: green;
      min-width: 0; /* NEW */
    }
    
    .container2 {
      display: flex;
      height: 30px;
      background-color: yellow;
    }
    
    .grow2a {
      flex-grow: 1;
      flex-basis: 400px;
      height: 20px;
      background-color: turquoise;
    }
    
    .grow2b {
      flex-grow: 1;
      width: 400px;
      height: 20px;
      background-color: turquoise;
    }
    <div class="container1">
      <div class="grow1">
        <div class="container2">
          <div class="grow2a">Working (flex-basis)</div>
        </div>
      </div>
    </div>
    
    <div class="container1">
      <div class="grow1">
        <div class="container2">
          <div class="grow2b">Not working (width)</div>
        </div>
      </div>
    </div>

    revised fiddle 1


    Solution for IE11

    In IE11, contrary to spec guidance, the flex min-width / min-height default values are already 0, yet the flex item still breaks out.

    The defaults are 0 because when the flexbox spec was first released, the min-* properties did not deviate from the CSS 2.1 initial values, which are 0.

    Later, after browsers had completed their implementations, the flex min-* values were updated to auto. Chrome, Safari, FF and Edge made the update. IE11 did not.

    The reason the flex items break out in IE11 relates to another issue: the browser wants an explicit width on the container

    In your code, add flex-basis: 100% to .grow1.

    More details here:

    • Why IE11 doesn't wrap the text in flexbox?
    • flexbox flex-basis: 0px in Chrome

    .container1 {
      margin-top: 10px;
      display: flex;
      width: 200px;
      height: 50px;
      background-color: red;
    }
    
    .grow1 {
      flex-grow: 1;
      height: 40px;
      background-color: green;
      flex-basis: 100%; /* NEW */
    }
    
    .container2 {
      display: flex;
      height: 30px;
      background-color: yellow;
    }
    
    .grow2a {
      flex-grow: 1;
      flex-basis: 400px;
      height: 20px;
      background-color: turquoise;
    }
    
    .grow2b {
      flex-grow: 1;
      width: 400px;
      height: 20px;
      background-color: turquoise;
    }
    <div class="container1">
      <div class="grow1">
        <div class="container2">
          <div class="grow2a">Working (flex-basis)</div>
        </div>
      </div>
    </div>
    
    <div class="container1">
      <div class="grow1">
        <div class="container2">
          <div class="grow2b">Not working (width)</div>
        </div>
      </div>
    </div>

    revised fiddle 2 (IE11)


    More Browser Discrepancies

    Evidence appears to exist (in this question and other examples I've seen) that Webkit-based browsers are no longer honoring the auto default defined in the spec.

    Moreover, the adherence to the auto standard may vary based on which property is used for sizing: flex-basis vs. width / height

    As discussed in the following post, these properties should render the same way.

    • What are the differences between flex-basis and width?
    0 讨论(0)
提交回复
热议问题