0

I have the following code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <style>
      *,
      *:before,
      *:after {
        box-sizing: border-box;
      }

      .list {
        line-height: 22px;
      }

      .list:before,
      list:after {
        display: table;
        content: "";
      }

      .list:after {
        clear: both;
      }

      .right-item {
        float: left;
        width: 50px;
        height: 50px;
        display: table;
        background-color: blue;
        border: 1px solid green;
        display: table;
        float: left;
        width: 50px;
        height: 50px;
        margin-right: 8px;
        margin-bottom: 8px;
        text-align: center;
        vertical-align: top;
      }

      .wrapper {
        display: inline-block;
        width: 100%;
      }

      .wrapper:before,
      .wrapper:after {
        content: "";
        display: table;
      }

      .wrapper:after {
        clear: both;
      }

      .floated-item {
        float: left;
        width: 50px;
        height: 50px;
        background-color: red;
        border: 1px solid black;
        margin: 0 8px 8px 0;
      }

      .flex-item {
        flex: auto;
        max-width: 100%;
      }

      .flex-container {
        display: flex;
        align-items: center;
        min-height: 15px;
        position: relative;
        align-items: center;
      }

      .flex-column {
        display: flex;
        flex-direction: column;
        flex-grow: 1;
        min-height: 1px;
        position: relative;
        max-width: 100%;
      }

      .outer-wrapper {
        display: flex;
        flex-flow: column wrap;
        margin-bottom: 24px;
        vertical-align: top;
      }

      .label {
        flex-grow: 0;
        overflow: hidden;
        display: inline-block;
        position: relative;
        max-width: 100%;
        min-height: 1px;
      }

      .label-inner {
        height: auto;
        position: relative;
        display: inline-flex;
        align-items: center;
        margin: 0;
      }
    </style>
  </head>
  <body>
    <form>
      <div class="outer-wrapper">
        <div class="label"><label class="label-inner">Label</label></div>
        <div class="flex-column">
          <div class="flex-container">
            <div class="flex-item">
              <span class="wrapper">
                <div class="list">
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
                  </div>
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
                  </div>
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
                  </div>
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
                  </div>
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
                  </div>
                </div>
                <div class="right-item"></div>
              </span>
            </div>
          </div>
        </div>
      </div>
    </form>
    <div>content</div>
  </body>
</html>

At first, I didn't have a clue what happens with the added extra space. After a long debugging, the problem is (at least it seems to be, it fixes the extra space, but maybe something else causes it, I don't know) that flex-wrap: wrap is used on the .outer-wrapper. When I set it to flex-wrap: nowrap it fixes the extra space.

I went through the Flexbox specification, and also through the Visual Formatting Model of the CSS spec, about float usage, formatting contexts, etc. but I still don't know what might be the problem.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
LearningMath
  • 851
  • 4
  • 15
  • 38
  • 3
    The problem seems to be caused by the floated item. If you remove the `float: left` and `display: table` from the `.right-item`, the problem goes away. I'm not exactly sure how the float and flex specs work in conjunction as you have it, but the browser seems to be interpreting the extra white space as the height of the floated item. – Steven Lambert Apr 28 '20 at 01:17
  • The desired layout is without the extra space in the bottom. I want to understand how the different layout mechanisms work with each other according to the specification, and I can't explain to myself why this doesn't work. I would appreciate it if someone explains how everything fits together according to the spec. – LearningMath Apr 28 '20 at 02:23
  • I wouldn't put so much weight on the specs in this case. `column wrap` is still riddled with bugs across all browsers. https://stackoverflow.com/a/61172784/3597276 – Michael Benjamin Apr 28 '20 at 03:15
  • Yeah, I agree. Do you have an idea what particular bug is this? It seems to increase the item's height in this case. I suppose it doesn't make the flex-container a multi-line one, just increases the item's height. What are your thoughts? – LearningMath Apr 28 '20 at 10:36
  • I'm not sure which bug you're encountering, but maybe you can workaround it. Is this what you need? https://jsfiddle.net/r73tvhjg/ – Michael Benjamin Apr 28 '20 at 16:16
  • The bug I am encountering is that the '.flex-column' item gets extra height. Notice that when you hover over it, it is a certain height, but the children it has are just half its height. Its getting extra height and I can't explain why. I don't necessarily need a workaround, I just want to know what is causing the bug, is it me not understanding and not knowing the specs, and this is a valid behavior, or is it another flexbox related bug. What is your thinking about the cause of the bug? Thanks. – LearningMath Apr 28 '20 at 16:26
  • Before we get into this further, there is a syntax error in your CSS. You're missing a class selector on a pseudo element. See `list:after {}` Once you add the dot, the extra space is gone. – Michael Benjamin Apr 30 '20 at 17:41

3 Answers3

0

This is firstly connected with the flex-column. The flex-direction makes the next div (.flex-item) to take the full width. If you remove flex-direction:column in your code, the last div (right-item) will automatically fall on the next line.

Also if you specify width:100% to the flex-column, the space will disappear, as the container is sure he can fit all in one line.

Then you give your .flex-item class flex:auto witch is flex-basis property and according to css-tricks means that the extra space is distributed based on its flex-grow value. (if you remove this from your code, your right-item will also be on the next line since he will take only the required space for your wrapper and that will not change).

After that you specify to you wrapper* to have width 100% (if you just remove the width:100% from your .wrapper class, without touching the flex-direction or the flex:auto, the same thing will occur (the right-item will be on the next line).

The bottom line is that there are many reasons for the flex container to think that you need 2 rows to fit in all your elements. But because of the flex-direction, the flex:auto and the width:100% you force it all in one line.

So it may seem strange but when you combine to much display types (flex,inline and table) and you rely too much for containers to calculate their sizes this happens.

Berci
  • 2,876
  • 1
  • 18
  • 28
-1

The extra space is due to display: inline-block given to the .wrapper class.

Change display: inline-block to display: flex, this should fix the issue.

*,
*:before,
*:after {
  box-sizing: border-box;
}

.list {
  line-height: 22px;
}

.list:before,
list:after {
  display: table;
  content: "";
}

.list:after {
  clear: both;
}

.right-item {
  float: left;
  width: 50px;
  height: 50px;
  display: table;
  background-color: blue;
  border: 1px solid green;
  display: table;
  float: left;
}

/* changed here */
.wrapper {
  display: flex;
  width: 100%;
}

.wrapper:before,
.wrapper:after {
  content: "";
  display: table;
}

.wrapper:after {
  clear: both;
}

.floated-item {
  float: left;
  width: 50px;
  height: 50px;
  background-color: red;
  border: 1px solid black;
  margin: 0 8px 8px 0;
}

.flex-item {
  flex: auto;
  max-width: 100%;
}

.flex-container {
  display: flex;
  align-items: center;
  min-height: 15px;
  position: relative;
  align-items: center;
}

.flex-column {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  min-height: 1px;
  position: relative;
  max-width: 100%;
}

.outer-wrapper {
  display: flex;
  flex-flow: column wrap;
  margin-bottom: 24px;
  vertical-align: top;
}

.label {
  flex-grow: 0;
  overflow: hidden;
  display: inline-block;
  position: relative;
  max-width: 100%;
  min-height: 1px;
}

.label-inner {
  height: auto;
  position: relative;
  display: inline-flex;
  align-items: center;
  margin: 0;
}
<div class="outer-wrapper">
  <div class="label"><label class="label-inner">Label</label></di <div class="flex-column">
    <div class="flex-container">
      <div class="flex-item">
        <span class="wrapper">
                <div class="list">
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
      </div>
      <div class="floated-item">
        <span><div class="floated-item"></div></span>
      </div>
      <div class="floated-item">
        <span><div class="floated-item"></div></span>
      </div>
      <div class="floated-item">
        <span><div class="floated-item"></div></span>
      </div>
      <div class="floated-item">
        <span><div class="floated-item"></div></span>
      </div>
    </div>
    <div class="right-item"></div>
    </span>
  </div>
</div>
</div>
</div>
<div>content</div>

Note: height of .outer-wrapper gets changed when inline-block is applied on .wrapper.

Ismail Vittal
  • 1,077
  • 9
  • 12
-1

As the container element <span class="wrapper"> if set to display:flex, it's somehow calculating its height as the sum of the height of the class="list" and class="right-item". It's somehow considering what height the class="list" elements would have taken up if it had no float elements in it(or would have clearfix hack applied on it). I am sure of this thing as if I change the height of the blue box to 20 px the height at the bottom also reduces(it's not always double of its actual content's height).

Code snippet with float elements in class='list' div

.right-item {
  animation: myfirst 5s linear infinite alternate;
}

@keyframes myfirst {
  0% {
    height: 50px;
  }
  100% {
    height: 10px;
  }
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <style>
    *,
    *:before,
    *:after {
      box-sizing: border-box;
    }
    
    .list {
      line-height: 22px;
    }
    
    .list:before,
    list:after {
      display: table;
      content: "";
    }
    
    .list:after {
      clear: both;
    }
    
    .right-item {
      float: left;
      width: 50px;
      height: 50px;
      display: table;
      background-color: blue;
      border: 1px solid green;
      display: table;
      float: left;
      width: 50px;
      height: 50px;
      margin-right: 8px;
      margin-bottom: 8px;
      text-align: center;
      vertical-align: top;
    }
    
    .wrapper {
      display: inline-block;
      width: 100%;
    }
    
    .wrapper:before,
    .wrapper:after {
      content: "";
      display: table;
    }
    
    .wrapper:after {
      clear: both;
    }
    
    .floated-item {
      float: left;
      width: 50px;
      height: 50px;
      background-color: red;
      border: 1px solid black;
      margin: 0 8px 8px 0;
    }
    
    .flex-item {
      flex: auto;
      max-width: 100%;
    }
    
    .flex-container {
      display: flex;
      align-items: center;
      min-height: 15px;
      position: relative;
      align-items: center;
    }
    
    .flex-column {
      display: flex;
      flex-direction: column;
      flex-grow: 1;
      min-height: 1px;
      position: relative;
      max-width: 100%;
    }
    
    .outer-wrapper {
      display: flex;
      flex-flow: column wrap;
      margin-bottom: 24px;
      vertical-align: top;
    }
    
    .label {
      flex-grow: 0;
      overflow: hidden;
      display: inline-block;
      position: relative;
      max-width: 100%;
      min-height: 1px;
    }
    
    .label-inner {
      height: auto;
      position: relative;
      display: inline-flex;
      align-items: center;
      margin: 0;
    }
  </style>
</head>

<body>
  <form>
    <div class="outer-wrapper">
      <div class="label"><label class="label-inner">Label</label></div>
      <div class="flex-column">
        <div class="flex-container">
          <div class="flex-item">
            <span class="wrapper">
                <div class="list">
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
        </div>
        <div class="right-item"></div>
        </span>
      </div>
    </div>
    </div>
    </div>
  </form>
  <div>content</div>
</body>

</html>

Code snippet with elements that are float inside class="list" div but also have clearfix hack applied on it.(To show what height it actually should have taken and which seems to cause the extra space in the above snippet)

.clearfix::after {
  content: "";
  clear: both;
  display: table;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <style>
    *,
    *:before,
    *:after {
      box-sizing: border-box;
    }
    
    .list {
      line-height: 22px;
    }
    
    .list:before,
    list:after {
      display: table;
      content: "";
    }
    
    .list:after {
      clear: both;
    }
    
    .right-item {
      float: left;
      width: 50px;
      height: 50px;
      display: table;
      background-color: blue;
      border: 1px solid green;
      display: table;
      float: left;
      width: 50px;
      height: 50px;
      margin-right: 8px;
      margin-bottom: 8px;
      text-align: center;
      vertical-align: top;
    }
    
    .wrapper {
      display: inline-block;
      width: 100%;
    }
    
    .wrapper:before,
    .wrapper:after {
      content: "";
      display: table;
    }
    
    .wrapper:after {
      clear: both;
    }
    
    .floated-item {
      float: left;
      width: 50px;
      height: 50px;
      background-color: red;
      border: 1px solid black;
      margin: 0 8px 8px 0;
    }
    
    .flex-item {
      flex: auto;
      max-width: 100%;
    }
    
    .flex-container {
      display: flex;
      align-items: center;
      min-height: 15px;
      position: relative;
      align-items: center;
    }
    
    .flex-column {
      display: flex;
      flex-direction: column;
      flex-grow: 1;
      min-height: 1px;
      position: relative;
      max-width: 100%;
    }
    
    .outer-wrapper {
      display: flex;
      flex-flow: column wrap;
      margin-bottom: 24px;
      vertical-align: top;
    }
    
    .label {
      flex-grow: 0;
      overflow: hidden;
      display: inline-block;
      position: relative;
      max-width: 100%;
      min-height: 1px;
    }
    
    .label-inner {
      height: auto;
      position: relative;
      display: inline-flex;
      align-items: center;
      margin: 0;
    }
  </style>
</head>

<body>
  <form>
    <div class="outer-wrapper">
      <div class="label"><label class="label-inner">Label</label></div>
      <div class="flex-column">
        <div class="flex-container">
          <div class="flex-item">
            <span class="wrapper">
                <div class="list clearfix">
                  <div class="floated-item">
                    <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
          <div class="floated-item">
            <span><div class="floated-item"></div></span>
          </div>
        </div>
        <div class="right-item"></div>
        </span>
      </div>
    </div>
    </div>
    </div>
  </form>
  <div>content</div>
</body>

</html>

I will try to find some reference of why exactly is this happening and edit this post in case I do find it. But, in my understanding, flex and float are very contradicting to each other in terms of how they behave. In case you are bound on using them together then you must know why, what, how etc. of both of them in details. Or else just refrain from using both of them together.

Also, one important thing about your code above is that you are using display: flex and then using flex-flow: column wrap; on outer-wrapper div with just 1 single child element in it. I don't see the point of adding these styles. As there is only 1 element inside outer-wrapper div, it would have behaved in the same way only without those styles also. Try to use display: flex only when required.

Nandita Sharma
  • 13,287
  • 2
  • 22
  • 35
  • The bounty note states: *"I would like a clear description what causes the bug, if it is a bug, or what spec rules make it behave like it does."* Your answer states *"...it's somehow calculating..."* and *"It's somehow considering..."* and *"I will try to find some reference..."* You're not meeting the standard requested. If you can improve your answer, I'll be happy to reverse my downvote. – Michael Benjamin May 06 '20 at 21:42
  • @MichaelBenjamin Thanks for clarifying that. I do not mind the downvote. When I posted this answer I knew what I was doing and knew this is bound to happen :) . I will surely try to find an answer. But sometimes it's better to put thoughts in open so that someone else may get another direction of looking into the issue. I did not really post only for the bounty. And in any case it's the decision of OP to award bounty or not :) So I won't mind if he/she doesn't give that to anyone if he/she is not fully satisfied with any answers. – Nandita Sharma May 07 '20 at 06:38