13

I'm trying to make a fixed-size content reader with a title. The title should be shown even if the content scrolls. In this situation, I tried to make a structure like this using CSS3 flexbox:

.flex {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 150px;
    border: 1px solid #ddd;
}

.title {
    height: 50px;
    line-height: 50px;
    background: #eee;
}

.text-wrap {
    flex: 1 0 0;
}

.text {
    height: 100%;
    overflow-y: auto;
}
<div class="flex">
    <div class="title">Title</div>
    <div class="text-wrap">
        <div class="text">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas faucibus justo vitae urna lacinia pharetra. Quisque nulla lorem, laoreet quis dapibus nec, vehicula vitae lorem. Nunc fringilla justo vel metus rhoncus, at congue leo dictum. Morbi congue tortor lacinia, mollis sapien indsadsadf, rutrum purus. Nam ornare dapibus mi, vitae varius diam tincidunt id. Donec maximus sem nec luctus euismod. Morbi a volutpat diam. In sapien orci, auctor et facilisis eu, finibus ac mauris. Vivamus eu nunc porta, congue libero quis, rutrum nibh. Proin feugiat vel augue mattis cursus.</p>
        </div>
    </div>
</div>

so that the content gets the rest of the height no matter what the flex container's size is. However, as you can see, the content gets out of the container and the overflow-y property is not working.

However, if I specify the height to 0 in the text-wrap, I can see that my code is working, as the following:

.flex {
    display: flex;
    flex-direction: column;
    width: 100%;
    height: 150px;
    border: 1px solid #ddd;
}

.title {
    height: 50px;
    line-height: 50px;
    background: #eee;
}

.text-wrap {
    flex: 1 0 0;
    height: 0;
}

.text {
    height: 100%;
    overflow-y: auto;
}
<div class="flex">
    <div class="title">Title</div>
    <div class="text-wrap">
        <div class="text">
            <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas faucibus justo vitae urna lacinia pharetra. Quisque nulla lorem, laoreet quis dapibus nec, vehicula vitae lorem. Nunc fringilla justo vel metus rhoncus, at congue leo dictum. Morbi congue tortor lacinia, mollis sapien indsadsadf, rutrum purus. Nam ornare dapibus mi, vitae varius diam tincidunt id. Donec maximus sem nec luctus euismod. Morbi a volutpat diam. In sapien orci, auctor et facilisis eu, finibus ac mauris. Vivamus eu nunc porta, congue libero quis, rutrum nibh. Proin feugiat vel augue mattis cursus.</p>
        </div>
    </div>
</div>

I can't understand this behavior. I understand that flex-basis is a property which decides the initial height of the element (since the flex-direction is set to column), and that the flexbox divides the remaining heights to the elements according to the flex-grow property.

Then in this case, since the text-wrap's flex-basis(initial height) is set to 0 and it is the only element that has the property flex-grow, shouldn't the height be fixed to the rest of the flex container? Why is this behavior happening?

In addition, why should I specify the height: 0 property to the text-wrap in order to make my code work?

Thanks very much.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Suhjin Park
  • 440
  • 3
  • 11

1 Answers1

19

Your code is correct and working properly.

There is just one more flexbox feature you need to factor in:

An initial setting on a flex container is min-height: auto. This means that, by default, a flex item cannot be shorter than its content. Once you override this setting, your layout works as expected.

You could use height: 0, but here's the standard method:

.text-wrap {
    flex: 1 0 0;
    min-height: 0; /* new */   
}

Full explanation here: Why doesn't flex item shrink past content size?

.flex {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 150px;
  border: 1px solid #ddd;
}
.title {
  height: 50px;
  line-height: 50px;
  background: #eee;
}
.text-wrap {
  flex: 1 0 0;
  min-height: 0; /* new */
}
.text {
  height: 100%;
  overflow-y: auto;
}
<div class="flex">
  <div class="title">Title</div>
  <div class="text-wrap">
    <div class="text">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas faucibus justo vitae urna lacinia pharetra. Quisque nulla lorem, laoreet quis dapibus nec, vehicula vitae lorem. Nunc fringilla justo vel metus rhoncus, at congue leo dictum. Morbi
        congue tortor lacinia, mollis sapien indsadsadf, rutrum purus. Nam ornare dapibus mi, vitae varius diam tincidunt id. Donec maximus sem nec luctus euismod. Morbi a volutpat diam. In sapien orci, auctor et facilisis eu, finibus ac mauris. Vivamus
        eu nunc porta, congue libero quis, rutrum nibh. Proin feugiat vel augue mattis cursus.</p>
    </div>
  </div>
</div>
Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    Great answer! Now I can understand the behavior. However, I have heard that the value of `min-height` takes precedence on the value of `height`. Then, why would specifying height: 0 work, when `min-height: auto` overrides `height: 0`? – Suhjin Park Feb 09 '17 at 14:51
  • 2
    That's a great question (and one I was hoping you wouldn't ask because I had spent a few minutes trying to figure that out ;-) To get a complete explanation, I would post a new question. However, I'm somewhat certain the answer lies in [**this part of the flexbox spec**](https://www.w3.org/TR/css-flexbox-1/#min-size-auto), which states... – Michael Benjamin Feb 09 '17 at 15:11
  • 3
    *In general, the automatic minimum size is the smaller of its content size and its specified size.* Hence, when you added `height: 0`, that became the *specified size*, which became the automatic minimum size since it was smaller than the *content size*. – Michael Benjamin Feb 09 '17 at 15:12