1

Hi I have following HTML code (here is "working" example)

<div class="layout">
    <main class="main">
       <nav class="menu">
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
      </nav>

      <section class="main__content">
        Some Content
      </section>

    </main>
</div>

And style:

.layout {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.main {
    display: flex;
}

.menu {
    display: flex;
    border-right: solid 3px red;
    width: 258px;
    flex-direction: column;
}

.menu__item {
    height: 340px;
    width: 240px;
    margin: 10px;
    background: #aaaaaa;
}

The problem is that on Chrome, when screen height is smaller than left menu and scrollbar appear, then menu right border (red) will be not rendered when scrollbar is move down. Desired behaviour is to draw red border to the end of vertical menu (so if we move scrollbar we should always see red border). How to do it?

enter image description here

Asons
  • 84,923
  • 12
  • 110
  • 165
Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345

2 Answers2

3

This is the default behavior when it comes to block elements. They become as high or wide as their parent, inline elements on the other hand, they grow with content.

There is several solutions to make the red border size with content, and here are 3, where I used the 2 mentioned in your own answer, to explain why they work:

  1. Move it to the main children. This work because flex items behave like inline block, and grows with their content.

  2. Make the outer most have a non fixed height, in this case the layout, by using min-height instead. This work as the flex container is now allowed to be higher than full viewport.

  3. The main isn't allowed to grow but allowed to shrink due to the flex item default value is flex: 0 1 auto, so by setting it to flex: 1 0 auto those terms is swapped.

Stack snippet 1

.layout {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.main {
    display: flex;
}

.menu {
    display: flex;
    width: 258px;
    flex-direction: column;
}

.menu  > div {
    border-right: solid 3px red;
}

.menu__item {
    height: 340px;
    width: 240px;
    margin: 10px;
    background: #aaaaaa;
}
<div class="layout">
    <main class="main">
       <nav class="menu">
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
      </nav>

      <section class="main__content">
        Some Content
      </section>

    </main>
</div>

Stack snippet 2

.layout {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.main {
    display: flex;
}

.menu {
    display: flex;
    width: 258px;
    flex-direction: column;
    border-right: solid 3px red;
}

.menu__item {
    height: 340px;
    width: 240px;
    margin: 10px;
    background: #aaaaaa;
}
<div class="layout">
    <main class="main">
       <nav class="menu">
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
      </nav>

      <section class="main__content">
        Some Content
      </section>

    </main>
</div>

Stack snippet 3

.layout {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.main {
    flex: 1 0 auto;
    display: flex;
}

.menu {
    display: flex;
    width: 258px;
    flex-direction: column;
    border-right: solid 3px red;
}

.menu__item {
    height: 340px;
    width: 240px;
    margin: 10px;
    background: #aaaaaa;
}
<div class="layout">
    <main class="main">
       <nav class="menu">
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
            <div><div class="menu__item">Item</div></div>
      </nav>

      <section class="main__content">
        Some Content
      </section>

    </main>
</div>

When it comes to why the extra div wrapped around the menu__item work, is because a flex item by default always try to shrink-to-fit as it defaults to flex: 0 1 auto, but at the same time won't be smaller than its content, and as it is the extra div that is the flex item, with a sized content, it can.

When you use i.e. option 3 above, it will start to work without that div wrapper, as now the main is allowed to grow with its content, which will let the menu__item to keep its height.

Stack snippet

.layout {
    height: 100vh;
    display: flex;
    flex-direction: column;
}

.main {
    flex: 1 0 auto;
    display: flex;
}

.menu {
    display: flex;
    width: 258px;
    flex-direction: column;
    border-right: solid 3px red;
}

.menu__item {
    height: 340px;
    width: 240px;
    margin: 10px;
    background: #aaaaaa;
}
<div class="layout">
    <main class="main">
       <nav class="menu">
            <div class="menu__item">Item</div>
            <div class="menu__item">Item</div>
            <div class="menu__item">Item</div>
            <div class="menu__item">Item</div>
      </nav>

      <section class="main__content">
        Some Content
      </section>

    </main>
</div>
Asons
  • 84,923
  • 12
  • 110
  • 165
0

I don't know why chrome behave in this way, but we can at least two solutions:

  1. Change height: 100vh; in .layout class to min-height: 100vh;
  2. Add flex: 1 0 auto; to .main class

May be someone can explain why chrome behave like this and why above solutions works?

I alsow wonder why if I change <div><div class="menu__item">Item</div></div> to <div class="menu__item">Item</div> all items will be squeezed to screen size ? (and in this case scrollbar (and problem) will disappear but not in acceptable way)

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345