Flex item not filling screen height with "align-items: stretch" - html

With body's flex-direction: row;, I am expecting its align-items: stretch; will stretch the child item vertically to fill the screen height. I don't understand why this is not happening.
Here's a minimal example of what I am trying to do. I am expecting the blue block to fill the entire green body.
body {
display: flex;
flex-direction: row;
align-items: stretch;
align-content: stretch;
background-color: green;
}
.flexContainer {
display: flex;
background-color: blue;
}
<body>
<div class="flexContainer">
Hello
</div>
</body>
https://jsfiddle.net/qc6fu1b3/

It's not happening because the height of body is the height of the content.
See the red border around body in your code: https://jsfiddle.net/qc6fu1b3/2/
As you can see, align-items: stretch has no space to work.
Unlike width, which block elements fill 100% by default, heights must be defined. Otherwise, elements default to auto – the height of the content.
When you say:
I am expecting [...] the child item vertically to fill the screen height.
There's no reason to expect this with CSS default behavior. If you want the element to expand the height of the screen, then define that in your code:
html { height: 100%; }
body {
height: 100%;
display: flex;
flex-direction: row;
align-items: stretch;
align-content: stretch;
background-color: green;
}
.flexContainer {
display: flex;
background-color: blue;
}
<body>
<div class="flexContainer">Hello</div>
</body>

Related

Weird flex wrap positioning with vertical scroll

I have a container with a number of cards inside. I want the cards to wrap horizontally within a scroll-able window, which is working for the most part, but there is a gap between the 2nd row of the wrapped items and the first, instead of lining up right underneath the first row.
When I remove the overflow-y and height that enable the scroll bar, the flex wrap works as expected.
Here's the rule for that container:
.cards {
display: flex;
flex-wrap: wrap;
margin: 1rem;
/* this adds the scroll but screws
up the flex-wrap */
height: 70vh;
overflow-y: scroll;
}
Here's the JSFiddle: https://jsfiddle.net/n9w2vb0m/3/
New CSS.
Now everything is as the author wanted, no distance between cards.
.main {
display: flex;
flex-direction: column;
/*justify-content: space-between;*/
height: 100%;
}
.cards {
display: flex;
flex-wrap: wrap;
margin: 1rem;
/*height:70vh*/
overflow-y: scroll;
}
.bottom-bar{
margin-top:auto
}

Why is the container for h1 is a lot bigger than it needs to be?

I've started learning flexbox recently and tried doing some exercises to practice but I got stuck because the container for h1 is a lot bigger than it needs to be, even if margin and padding are 0, and it makes the whole other page uncentered.
main {
display: flex;
justify-content: center;
background-color: #cacaca;
height: 100vh;
flex-flow: row wrap;
}
h1 {
margin: 0;
padding: 0;
}
#container {
margin-top: 100px;
}
<main>
<h1>Here are some nice pics</h1>
<div id="container"> ... </div>
</main>
It's because default value of align-items is stretch which makes all flex items to stretch to full height of their parent. if you give align-item: flex-start to use only required height.
main {
height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
}
h1 {
background: red;
}
<main>
<h1>Here are some nice pics</h1>
<div id="container">Container</div>
</main>

What is the difference between the flex and height properties?

Given the following example, both will fill out the center to consume the remaining space in the page, given the page is using flex. I am leaning towards using the css property flex vs height in the body. Is there a difference that needs to be considered when applying one over the other?
CSS
.page {
display: flex;
flex-direction: column;
}
.header {
height: 100px;
}
.body {
flex: 1; // vs height: 100%;
}
.footer {
height: 40px;
}
HTML
<div class="page">
<div class="header">Sample Header</div>
<div class="body">Sample Body</div>
<div class="footer">Sample Footer</div>
</div>
When you set an element to flex: 1, that breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
In a column-direction container (like you have), the flex properties above apply vertically. This means that flex-basis and height are equivalent properties.
flex-basis = height (in a column-direction container)
There is an obvious difference between flex-basis: 0 and height: 100%. It's the same difference as height: 0 and height: 100%.
In your situation, where there is a .header and a .footer consuming 140px of vertical space, setting the middle item (.body) to height: 100% would normally cause an overflow.
But since an initial value of a flex container is flex-shrink: 1, flex items are permitted to shrink, and this wouldn't happen. However, it's still sloppy and imprecise coding, in my view.
By setting .body to flex: 1, you're setting the height to 0, but also allowing it to consume free height with flex-grow: 1. I would say, in this case, that this solution is more efficient.
More details:
What are the differences between flex-basis and width?
§ 7.1.1. Basic Values of flex
There is a huge difference between flex and height.
First to answer your question.
Height 100% doesn't use the remaining space. It will use all the spaces of parent, in your case if page dom is height 200px; then body will also be height: 200px;.
Flex will be correct solution here to fill up the space (flex: 1).
Flex is more than filling the space, its more of a layout and it has influences on its child, how they position and align.
Try below code
.page {
display: flex;
flex-direction: column;
height: 100%;
}
.header {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.body {
display: flex;
flex-direction: column;
height: 80vh;
align-items: center;
justify-content: center;
}
.footer {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
<div class="page">
<div class="header">Sample Header</div>
<div class="body">Sample Body</div>
<div class="footer">Sample Footer</div>
</div>

Horizontal Margins going outside of parent div in flexbox

I'm getting some unexpected behavior with my margins using flex and I would like some help in understanding why.
I'v got some simple html like so:
<div className="dashboard">
<div className="dashboard__inner-container">Inner Container</div>
</div>
And my scss file looks like this:
.dashboard {
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
flex: 1 1 auto;
background-color: #f4f6f8;
}
.dashboard__inner-container {
display: flex;
flex-direction: column;
background-color: #ffffff;
flex: 1 1 auto;
width: 100%;
margin: 100px 50px;
}
What I am expecting is that the inner container will completely fill up the parent container, minus 100px on the top and bottom and 50px on the right and left. The vertical margin works as expected, but the horizontal margin actually extends out of the parent div, so that the inner container still appears to be taking up the entire width of the parent div.
I'm not sure if this is related to flexbox or not.
Here is an isolated CodePen https://codepen.io/MaxMillington2/pen/EQWZoj
When using align-items: center with column direction, the item will collapse to its content width, instead of with its default, stretch, which makes it fill its parent's width.
Additionally, when setting width: 100% to the inner, it will override the default stretch, which will make the item be 100% of parent's width + margin.
For the expected output, remove align-items: center on the outer and width: 100% on inner.
Stack snippet
html {
height: 100%;
overflow: auto;
}
.outer {
display: flex;
justify-content: center;
flex-direction: column;
background-color: #f4f6f8;
height: 100%;
}
.inner {
display: flex;
flex-direction: column;
background-color: #ffffff;
flex: 1 1 auto;
text-align: center;
margin: 100px 80px;
}
<div class='outer'>
outer
<div class='inner'>
inner
</div>
</div>

Flex item won't consume available space in container when second flex item introduced

I have a container named #center in which I want to display canvas and a button inside it. I want the canvas object to take all the available space (respecting the button inside the container).
This is my code:
html, body {
width: 100%;
height: 100%;
}
#container {
display: flex;
height: 100%;
background-color: blue;
}
.block {
flex: 1;
}
#left {
background-color: green;
}
#center {
display: flex;
flex: 1;
flex-wrap: wrap;
align-content: flex-start;
}
#right {
background-color: orange;
}
#canvasObject {
display: block;
margin: 0 auto;
border: 1px solid;
background-color: yellow;
}
<div id="container">
<div id="left" class="block">Left</div>
<div id="center" class="block">
<canvas id="canvasObject">Your browser does not support Canvas.</canvas>
<button type="button">Click!</button>
</div>
<div id="right" class="block">Right</div>
</div>
If I do not have any button in my code, canvas occupy the full div but when I display the button, canvas does not seem to resize the desired height.
Example 1: Without button.
Example 2. With button.
How can I make that the canvas object will resize until the available height (also width but it is already doing it)?
Thanks in advance!
The problem is that you have align-content: flex-start on a row-direction flex container:
#center {
display: flex;
flex: 1;
flex-wrap: wrap;
align-content: flex-start; /* <-- source of the problem */
}
The align-content property controls the spacing between flex items in the cross-axis when there are multiple lines in the container.
When the button element is excluded, there is only one line in the flex container. In such a case, align-content has no effect (align-items would work).
But when you add the button, there are now two lines on wrap, and align-content takes over (align-items does not work).
Since align-content is set to flex-start in your code, both lines are packed to the top of the container. (For other options, try flex-end, center, space-between, space-around and stretch).
An efficient solution would be to use flex-direction: column and apply flex: 1 to the canvas.
#center {
display: flex;
flex-direction: column; /* new; stack flex items vertically */
flex: 1;
flex-wrap: wrap;
/* align-content: flex-start; <-- remove; not necessary */
}
#canvasObject {
flex: 1; /* new; consume all available free space */
/* display: block; <-- remove; not necessary */
/* margin: 0 auto; <-- remove; not necessary */
border: 1px solid;
background-color: yellow;
}
Revised Fiddle
W3C References:
8.4. Packing Flex Lines: the align-content property
8.3. Cross-axis Alignment: the align-items and align-self properties