This behavior is a little odd and weird. If there is a container with its display
property set to flex
and flex-direction
to column
, the orientation of the <hr>
elements inside it will change and become vertical and its height will decrease to fit the height of the line.
html, body {
height: 100%;
}
body {
font-family: sans-serif;
}
.container {
padding: 20px;
height: 100%;
display: flex;
flex-direction: column;
flex-grow: 1;
}
<div class="container">
<h3>Title</h3>
<hr/>
<div class="content">
<p>This is some content</p>
</div>
</div>
Check out this pen.
This behavior is confirmed on Firefox and Chrome. I didn't find any explanation for it. How can I fix it?
According to HTML5 Rendering - The hr
element, it is expected to be rendered with this style:
hr { color: gray; border-style: inset; border-width: 1px; margin: 0.5em auto; }
Specifically, note margin-left: auto
, margin-right: auto
.
Those styles are used to center a block element horizontally. According to Calculating widths and margins - Block
If both margin-left
and margin-right
are auto
, their used values
are equal. This horizontally centers the element with respect to the
edges of the containing block.
In a block layout this effect is only noticeable if the block has an explicit width, otherwise the block will grow to cover all its containing block.
In Flexbox it's similar: the default align-self: auto
and align-items: stretch
make flex items grow to cover the flex line in the cross axis (horizontal one in column layout), and auto
margins can also be used to center.
However, there is a big difference: according to Cross Size Determination, align-self: stretch
does not affect flex items with auto
margins:
If a flex item has align-self: stretch
, its computed cross size
property is auto
, and neither of its cross-axis margins are auto
,
the used outer cross size is the used cross size of its flex line,
clamped according to the item’s min and max cross size properties.
Otherwise, the used cross size is the item’s hypothetical cross
size.
Then, you can fix this problem by removing the auto
margins:
hr {
margin-left: 0;
margin-right: 0;
}
.container {
padding: 20px;
display: flex;
flex-direction: column;
}
hr {
margin-left: 0;
margin-right: 0;
}
<div class="container">
<h3>Title</h3>
<hr />
<div class="content">
<p>This is some content</p>
</div>
</div>
Alternatively, forcing a certain width through width
or min-width
would counteract the shrinking (more technically, the lack of stretch) caused by the auto
margins.
I found that setting the width of the <hr>
too 100%
fix the problem. Still odd, I have no idea why this happen.
Here is a pen
Try enclosing your hr
in another flex-item (like a div
, span
or something else) as following. This will resolve your issue.
Reason why this works is all children of a flex box container are flex-items. So in your case hr
was a flex-item. That's why its styling got effected. When you make this hr
a grand-child of the flex box container, it will no longer effect its styling.
That's why we added <div>
as parent of <hr/>
. <div>
becomes flex-item of your flex container. <hr>
is no more a flex-item.
html, body {
height: 100%;
}
body {
font-family: sans-serif;
}
.container {
padding: 20px;
height: 100%;
display: flex;
flex-direction: column;
flex-grow: 1;
}
<div class="container">
<h3>Title</h3>
<div><hr/></div>
<div class="content">
<p>This is some content</p>
</div>
</div>
Further Reading (Highly recommended):
- Basic Concepts of Flexbox
- Ordering Flex Items