3

See this fiddle:

https://jsfiddle.net/9hnj0b8v/3/

The only differnce in the two elements:

.label1
{
  display: inline-block;
}

.label2
{
  display: flex;
}

So the two labels are identical except one is set to inline-block and one to flex. Why do they have a different width? Why is one exceeding its container and the other does not?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
no_gravity
  • 579
  • 1
  • 3
  • 14
  • Somebody tried to remove the link to jsfiddle. Please do not do that. This is one is much clearer to see and work on in a fiddle. – no_gravity Feb 20 '19 at 12:51
  • 1
    It is much better to have it inline in a snippet. If the fiddle link dies the question loses information. – James Coyle Feb 20 '19 at 12:52
  • Sometimes it helps to use transitions to understand what's going on. I've taken the liberty of forking your fiddle and adding a transition that changes the width of the encapsulating div. Check it out here: https://jsfiddle.net/x6prc01w/ - hover the grey div to watch it in play. Change the styles of the other elements and add a float to the top span. I see no bugs or errors in your fiddle. Everything renders as expected. – MassDebates Feb 20 '19 at 13:31

3 Answers3

2

You are styling span elements with display: inline-block. By default, block level elements are 100% of the width of their parent container. As you are forcing the input and span onto the same line with white-space: nowrap, this forces the span to break out of the boundary of the parent container.

Why do they have a different width? Why is one exceeding its container and the other does not?

Using display: flex allows child elements to shrink to fit the available space so the span element starts with the 100% width of its parent but then shrinks down to fill the available space instead.

James Coyle
  • 9,922
  • 1
  • 40
  • 48
  • should I also say that *you edited your answer to include information from mine*? ;) – Temani Afif Feb 20 '19 at 18:41
  • "By default, block level elements are 100% of the width of their parent container." - that would explain it. But it is not always the case. Check this fiddle for a counter example: https://jsfiddle.net/7osrmkph/ – no_gravity Feb 24 '19 at 15:07
1

The main difference I observed is that with an inline-block, it will fill your parent div with your inline-block elements regardless of how many elements are in your parent div, however with display: flex will divide your parent div width (or height) with the number of element you have.

Also, in your fiddle, you've already set inline-block for the span, just try remove it and you'll see the difference in a more visual way

lucyjosef
  • 712
  • 1
  • 8
  • 24
1

It's because of the white-space:nowrap.

Without you will have this which is an expected result:

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 200px;
  background: #f0f0f0;
}

span {
  display: inline-block;
  white-space: normal;
  vertical-align: top;
}

label {
  margin-top: 10px;
  /*white-space: nowrap;*/
}

.label1 {
  display: inline-block;
}

.label2 {
  display: flex;
}
<div>

  <label class=label1>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to inline-block. For some reason,
  it overflows the containing div. But why?
</span>
</label>


</div>

Note how the inline-block has its width equal to the container because there a lot of text and it will break so it's like having a width:100%. Then if you add white-space:nowrap you will simply disable the wrap and move that inline-block upper by keeping its width and you will create the overflow1

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 200px;
  background: #f0f0f0;
}

span {
  display: inline-block;
  white-space: normal;
  vertical-align: top;
}

label {
  margin-top: 10px;
  white-space: nowrap;
}

.label1 {
  display: inline-block;
}

.label2 {
  display: flex;
}
<div>

  <label class=label1>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to inline-block. For some reason,
  it overflows the containing div. But why?
</span>
</label>


</div>

For the flexbox it's different because the wrap is controlled by flex-wrap that is by default nowrap. Notice that inline-block inside flexbox container are usless because element will be blockified when they become flex items.

Enable the wrap and you will have a similar behavior to the first example:

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 200px;
  background: #f0f0f0;
}

span {
  display: inline-block;
  white-space: normal;
  vertical-align: top;
}

label {
  margin-top: 10px;
  /*white-space: nowrap;*/
}

.label1 {
  display: inline-block;
}

.label2 {
  display: flex;
  flex-wrap:wrap;
}
<div>

  <label class=label1>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to inline-block. For some reason,
  it overflows the containing div. But why?
</span>
</label>

  <label class=label2>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to flex. For some reason,
  it does not overflow the containing div. But why not?
</span>
</label>

</div>

Now add back the nowrap of the white-space:

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 200px;
  background: #f0f0f0;
}

span {
  display: inline-block;
  white-space: normal;
  vertical-align: top;
}

label {
  margin-top: 10px;
  white-space: nowrap;
}

.label1 {
  display: inline-block;
}

.label2 {
  display: flex;
  flex-wrap:wrap;
}
<div>

  <label class=label1>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to inline-block. For some reason,
  it overflows the containing div. But why?
</span>
</label>

  <label class=label2>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to flex. For some reason,
  it does not overflow the containing div. But why not?
</span>
</label>

</div>

Nothing will happen with the flexbox because we no more deal with text and inline element but it's about flex items thus the white-space has no effect there since they are block element and as stated above the wrapping is controlled by flex-wrap.

Another thing to note is that flex items will by default always shrink to fit their parent container which also explain why there is no overlow even if you set an explicit width:

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 200px;
  background: #f0f0f0;
}

span {
  display: inline-block;
  white-space: normal;
  vertical-align: top;
}

label {
  margin-top: 10px;
  white-space: nowrap;
}

.label1 {
  display: inline-block;
}

.label2 {
  display: flex;
}
<div>

  <label class=label1>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to inline-block. For some reason,
  it overflows the containing div. But why?
</span>
</label>

  <label class=label2>
 <input type=checkbox>
 <span style="width:200px;">
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to flex. For some reason,
  it does not overflow the containing div. But why not?
</span>
</label>

</div>

But if you disable the shrink you can have an overflow:

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 200px;
  background: #f0f0f0;
}

span {
  display: inline-block;
  white-space: normal;
  vertical-align: top;
}

label {
  margin-top: 10px;
  white-space: nowrap;
}

.label1 {
  display: inline-block;
}

.label2 {
  display: flex;
}
<div>

  <label class=label1>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to inline-block. For some reason,
  it overflows the containing div. But why?
</span>
</label>

  <label class=label2>
 <input type=checkbox>
 <span style="width:200px;flex-shrink:0">
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to flex. For some reason,
  it does not overflow the containing div. But why not?
</span>
</label>

</div>

And without explicit width you will have this:

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 200px;
  background: #f0f0f0;
}

span {
  display: inline-block;
  white-space: normal;
  vertical-align: top;
}

label {
  margin-top: 10px;
  white-space: nowrap;
}

.label1 {
  display: inline-block;
}

.label2 {
  display: flex;
}
<div>

  <label class=label1>
 <input type=checkbox>
 <span>
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to inline-block. For some reason,
  it overflows the containing div. But why?
</span>
</label>

  <label class=label2>
 <input type=checkbox>
 <span style="flex-shrink:0">
  Here is a long description for the option that is set via the checkbox
  on the left. The label is set to flex. For some reason,
  it does not overflow the containing div. But why not?
</span>
</label>

</div>

1 here is another example to illustrate the effect of the white-space:nowrap and how it doesn't change the width of element calculated before:

.box {
  width:200px;
  border:2px solid red;
}
.box span {
  border:2px solid green;
  white-space:normal;
  display:inline-block;
  vertical-align:top;
}
<div class="box">
  <span>lorem ipsume</span>
  <span> lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume</span>
  <span> lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume</span>
</div>

<div class="box" style="white-space:nowrap">
  <span>lorem ipsume</span>
  <span> lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume</span>
  <span> lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume lorem ipsume</span>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • I'm assuming OP intends the label text to be beside the checkbox like in the `display: flex` example. Your 'solution' breaks that. – James Coyle Feb 20 '19 at 12:49
  • @JamesCoyle *solution*? I am explaining not providing a solution ;) – Temani Afif Feb 20 '19 at 12:50
  • You haven't explained why the overflow is actually occuring. You provided a solution to stop the overflow and this has nothing to do with `flex-wrap` as flexbox isn't wrapping anything. And now you are editing your answer to provide information from my answer. – James Coyle Feb 20 '19 at 12:59
  • @JamesCoyle what is not clear in the first paragraphe that is explaining the overflow? I have also added a blod text to hightlight why it's happening – Temani Afif Feb 20 '19 at 13:01
  • @JamesCoyle and what information I copied from your answer? If it's about the last sentence, I have already provided an old answer (https://stackoverflow.com/a/49492522/8620333) explaining the shrink effect so I simply know this information like you do. – Temani Afif Feb 20 '19 at 13:11