Height of flex element is not respected unless display: table is set? - html

http://jsfiddle.net/u2zedzob/12/
<div class="wrapper">
<div class="main-content"></div>
<div class="footer"></div>
</div>
*, *:before, *:after {
box-sizing: border-box;
}
.wrapper {
background-color: red;
height: 300px;
width: 300px;
display: flex;
flex-direction: column;
}
.main-content {
height: 100%;
width: 100%;
background-color: green;
}
.footer {
height: 30px;
width: 100%;
background-color: blue;
display: table;
}
In this example, the footer's height is 30px and main-content grows to fill the rest of the space. Perfect!
However, if I remove the display: table property of footer -- its height becomes 27.266px. This can also be prevented by setting the footer's min-height to 30px.
I'm not too familiar with flex logic. Why is this happening? Is there a more elegant solution where the height of footer will be respected? Maybe a flex property I am missing?

When working with flex box model you do not need to set height property for the child elements which should scale. Instead you would use e.g. the flex-grow property. In the given case where just one element should be scaled a value of 1 would be appropriate (as no proportions need to be defined here).
Have a look at the updated example where the height of the .main-content element is scaled according to the available space and the height of the .footer element is retained correctly by 30px without setting the display property:
http://jsfiddle.net/u2zedzob/21/
For further information maybe check this guide:
http://css-tricks.com/snippets/css/a-guide-to-flexbox/
The flex-grow property is explained as:
This defines the ability for a flex item to grow if necessary. It
accepts a unitless value that serves as a proportion. It dictates what
amount of the available space inside the flex container the item
should take up.
If all items have flex-grow set to 1, every child will set to an equal
size inside the container. If you were to give one of the children a
value of 2, that child would take up twice as much space as the
others.

Related

Why's CSS percentage (%) height applied to grand-child of flex element?

I'm trying to check how CSS 100% height property works. But there's one thing I can't understand.
Why's 100% height working perfectly on .flex-grand-child (Chrome)? Does .flex-child have height property? So why it's even working???
Here's JSFiddle
html, body {
height: 100%;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.flex-parent {
flex: 1 0 auto;
display: flex;
}
.flex-child {
width: 300px;
}
.flex-grand-child {
height: 100%;
background-color: green;
}
<div class="container">
<div class="flex-parent">
<div class="flex-child">
<div class='flex-grand-child'></div>
</div>
</div>
</div>
This is a particular case where the browser can handle percentage value on height due to the stretch effect of flexbox. The flex-child has a default alignment equal to stretch which is equivalent to having height:100% then the flex-parent is also filling its parent height with flex-grow:1. At the end, the browser was able to correctly resolve the height:100% of flex-grand-child
If the flex item has align-self: stretch, redo layout for its contents, treating this used size as its definite cross size so that percentage-sized children can be resolved.ref
If you disable the stretch alignment, it will break:
html,
body {
height: 100%;
}
.container {
display: flex;
flex-direction: column;
height: 100%;
}
.flex-parent {
flex: 1 0 auto;
display: flex;
}
.flex-child {
width: 300px;
min-height: 200px;
align-self: flex-start; /*this will break it*/
border: 1px solid;
}
.flex-grand-child {
height: 100%;
background-color: green;
}
<div class="container">
<div class="flex-parent">
<div class="flex-child">
<div class='flex-grand-child'></div>
</div>
</div>
</div>
To use simple words: When having the stretch effect, the browser will first define the parent height based on its own parent (the content play no role here) then the browser will make the content height:100% of the previous calculated height. Without stretch the browser need to consider the content to define the height of the parent and here we will fall into the classic issue of percentage height.
Related question to get more cases where percentage can be resolved without having an explicit height defined on the parent element: Why is my Grid element's height not being calculated correctly?
Here is the relevant part of the specification dealing with this: https://www.w3.org/TR/css-sizing-3/#percentage-sizing
It's a bit complex but it's different from the CSS2 specification where percentage will always fail if the parent height is not specified:
If the height of the containing block is not specified explicitly (i.e., it depends on content height), and this element is not absolutely positioned, the value computes to 'auto'.
The .flex-parent element has flex-grow: 1 applied, giving it the full height of the .container (height: 100%). It also has display: flex applied, making it a flex container.
This latter setting automatically triggers align-items: stretch, which causes the flex item – .flex-child – to expand the full height of the container. So the .flex-child computes to height: 100%.
Modern browsers, now accepting flex heights as a reference point for children with percentage heights, set the child of the flex item – .flex-grand-child – to the full height of the parent, which is height: 100%.
More details here: Chrome / Safari not filling 100% height of flex parent
You have .container as a flex container with a flex-direction of column, so by default, the child element will stretch to fill. So .flex-parent is stretching to fill .container.
Since .flex-parent is also a flex-container, .flex-child is stretching to fill that.
Finally, since .flex-grand-child has height 100%, it is also filling the entire area.

I don't understand why my div with height auto is taking the full height of its parent

I have a div.grid that contains multiple div.column inside using flexbox. When a div.column increases in height due to having more content inside, all other div.column also increase in height.
It is to my understaind that this shouldn't help as their height is set to auto.
Also, my grid is using the flex display, with flex-wrap: wrap. I think is what is causing it, but I haven't found any explanation to why it is changing the children's height.
I have tried changing the following properties, in different combinations and manners, of parent and children: position, display, height.
These are the computed styles only, not my actual code.
div.grid {
display: flex;
flex-wrap: wrap;
width: 960px;
}
div.column {
display: block;
flex-basis: 37.5%;
flex-grow: 0;
flex-shrink: 0;
/* height is actually set to auto, but it is computed like this */
height: 132px;
}
<div class="grid">
<div class="column">something</div>
<div class="column">something<br>else<br>here</div>
<div class="column">something</div>
</div>
I expected the children to not fill the full height of the parent when the children don't all have the same amount of content.
As LGSon has asnwered in the comments:
Using flex: display automatically defaults align-items to stretch making the height of the children stretch to fill the height of the wrapper. It is also not shown in the computed properties, which is why it didn't cross my mind to check it.
Therefore, the solution was to add align-items: flex-start to .grid.

Why does width:auto behave differently than height:auto?

I don't get the auto value. If applied to height it will take on the child's height, but if applied to width it will take on the parent's width.
There are no MDN posts on the auto value itself, and Google yields "100% VS auto" hits rather than "width:auto VS height:auto" hits.
For my current needs I would like an element to expand to its child's width, but in general I wish to know what is the deal with auto.
.divXS {
width: 100px;
height: 100px;
background: green;
}
.divXXS {
width: 50px;
height: 50px;
background: yellow;
}
.divSM {
width: 200px;
height: 200px;
}
#Father {
background: blue;
border: 3px solid #20295E;
}
#Mother {
background: pink;
border: 3px solid #DB6DBE;
}
#Daughter {
width: 100%;
height: 100%;
}
#Son {
width: auto;
height: auto;
}
<div class="divSM" id="Mother">
<div class="divXS" id="Daughter">
<div class="divXXS" id="grandDaughter"></div>
</div>
</div>
<div class="divSM" id="Father">
<div class="divXS" id="Son">
<div class="divXXS" id="grandSon"></div>
</div>
</div>
jsFiddle / jsBin
'auto' doesn't even always behave the same way for the width property and the height property respectively. It can have different behaviors for the width property not only depending on the element's display type, but also depending on the value of other properties for the same display type. That's why it's called 'auto' — from my answer here,
The value of said property is adjusted automatically according to the content or the context of the element.
Based on your description I'm assuming your question is in the context of block layout. Block layout consists of a series of block-level boxes stacked vertically in normal flow.
So a block container box, by default, only has to grow tall enough to contain its descendants stacked vertically. And since block-level boxes never stack horizontally in normal flow, there's no reason they can't stretch to the full width of their containing block. (They don't even need to shrink to accommodate floats in the same block formatting context, though the line boxes inside them do, but that's a separate topic altogether.)
And that's why, in block layout, an auto height is based on the total height of descendants and an auto width is based on the containing block width.

In a flexbox layout, is there a `flex-shrink: 0` declaration for the cross axis?

I want to prevent elements in a flex container from shrinking in the dimension that is not the flex-direction. The following example has <article> elements side by side in a row. When the available vertical space is reduced, these elements do not force their flex container to display a scrollbar; instead the content overflows the element boundary.
Screenshot 1 - there is enough horizontal and vertical space to display everything:
Screenshot 2 - the reduced vertical space pushes the element border up:
Screenshot 3 - vertical space further reduced, container finally gets a scrollbar:
Screenshot 4 - without flex-shrink:0, the element widths (main flex axis) will also be reduced:
flex-shrink:0 can prevent horizontal shrinking, but how can I prevent the elements from shrinking vertically?
Giving the <article> elements overflow: auto or something similar does not give the desired result (= scrollbar on the container). Ideally, the display would look like this montage:
If I knew the elements' height in advance, I could give them a min-height, but that is not always the case.
FIDDLE: http://jsfiddle.net/twdan8u8/
HTML:
<main>
<article>article<br>article<br>article</article>
<article>article<br>article<br>article</article>
</main>
CSS:
* {
box-sizing: border-box; /* not the culprit */
}
html {
height: 100%;
}
body {
position: relative;
height: 100%;
margin: 0;
background: #999;
}
main {
overflow: auto;
background: gold;
display: flex;
height: 80%;
padding: 50px 30px;
}
article {
flex-shrink: 0;
font-size: 28px;
border: 2px solid red;
margin-right: 30px;
padding: 10px;
}
As is so often the case, I found the (or rather a) solution just when I finished writing the question. Since this might help somebody else, here's what I found out:
If the flex container is given the style align-items: flex-start, element heights are not reduced and the container gets a scrollbar when necessary (assuming a suitable overflow value).
The default for this property is "stretch". It can also be set on individual flex elements using align-self. The drawback is that the elements are now no longer equally high (i.e., they don't stretch to the full available height anymore).

Set number of div elements' width based on static width container

I want to set the width of the div elements' width accordingly depending on their container width. However, the number will be changed, so the width will need to be adjusted accordingly. Here is a CSSDeck link to explain the situation clearly:
http://cssdeck.com/labs/hvmkapkd
As you can see, both containers are identical (needed), also they have modular content (<div> elements) (which is also needed). Keeping the same structure, is it possible to auto adjust the width of the divs using CSS so that they fill up the whole container?
Then each item in the first container would have 33.333% width, and each item in the second container would have 20% width.
I found the solution right after posting the question.
Setting the .container elements as table and setting the colored content as table-cell made it.
Link is updated above, but here is the link once again anyway:
http://cssdeck.com/labs/hvmkapkd
Give the flex-box concept a chance (https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Flexible_boxes)
.container{
height: 100px;
width: 100px;
background-color: lightgray;
margin: 20px;
/* flexbox setup */
display: -webkit-flex;
-webkit-flex-direction: row;
display: flex;
flex-direction: row;
}
.container > div {
height: 100%;
/* flexbox setup */
-webkit-flex: 1 1 auto;
flex: 1 1 auto;
}
(http://cssdeck.com/labs/full/hvmkapkd)