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:
Move it to the main
children. This work because flex items behave like inline block, and grows with their content.
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.
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>