Flex box bug with max-height in chrome v43 - html

I have the following construct to render a simple layout with fixed header and footer and a flexible body that with scrollable content: http://jsbin.com/jokevuyave/1/edit?html,css
<div id="main-view">
<div class="rows">
<div class="head">header</div>
<div class="main scroll"></div>
<div>footer</div>
</div>
</div>
and this are the styles:
.rows,
.columns {
display: flex;
flex-direction: column;
box-sizing: border-box;
}
.columns {
flex-direction: row;
max-height: 100%;
overflow: hidden;
}
.main {
flex: 1;
}
.scroll {
display: flex;
overflow: hidden;
position: relative;
flex-direction: column;
}
.scroll > * {
margin: 0;
width: 100%;
overflow: auto;
}
html,
body,
#main-container,
#main-view,
.scrollable {
height: 100%;
margin: 0
}
#main-view > div {
max-height: 100%;
display: flex;
}
.head {
height: 120px
}
This construct works well in firefox and also in chrome until the version 43 was released. Now the height of the containers is wrong, header and footer don't expand to display its content and the content container lays over the header content. Any idea how to fix this?
Edit
The problem seems to be this line:
#main-view > div {
max-height: 100%;
}
The idea is that the box should only expand if the content is to large.
Change it to
#main-view > div {
height: 100%;
}
fix the wrong height for the inner container but now the box has always the height of 100%, even if the content is really small.

There is a problem with max-heigth and flexbox: flexbox misbehaving with max-height
So the solution is to set the flex property to every element insight rows container to 0
.rows .main {
flex: 1;
}
.rows > * {
flex: 0 0 auto
}

Related

div take all available height

I'm using the following HTML
<div className="App">
<div className="AppMenu">
Menu
</div>
<div className="AppContainer">
Test
</div>
</div>
and this CSS:
.App {
min-height: 100vh !important;
max-height: 100vh !important;
height: 100vh !important;
background-color: red;
}
.AppMenu {
background-color: blue;
position: sticky;
top: 0px;
width: 100%;
font-size: 1.3em;
}
.AppContainer {
background-color: green;
}
how can I set / calc AppContainer size to take all heigh => 100vh-(AppMenu height)
with CSS (or js) ?
You already using the full height of a screen with 100vh. There is no need to use a nuke like !important which nearly always just mask the issue instead of solving it. Also min-height: 100vh; + max-height: 100vh; can be considered as bad coding. In this case you want a definite height of 100vh which is done by height: 100vh;. So you having 3 lines of code where you actually only would need 1.
The issue that you get a scrollbar and the screen is overflowing is caused by the default body margin. The element will be 100vh tall and use the default body amrgin which will cause an document height of more then 100vh. Therefor simply reset the default body amrgin to 0 with: body { margin: 0; }
However with that soultion you will have a potencial overflow issue. So you should either set an overflow rule to the container or use min-height instead.
To have the the AppContainer fill the remaining height there are multiple ways to solve it. The easiest way to solve it would be the sue of a CSS-Grid with grid-template-rows: min-content auto;. That way, the Menu will take up as much space as needed and the remining height will be used be the AppContainer.
body {
margin: 0;
}
.App {
height: 100vh;
background-color: red;
display: grid;
grid-template-rows: min-content auto;
}
.AppMenu {
background-color: blue;
position: sticky;
top: 0px;
font-size: 1.3em;
}
.AppContainer {
background-color: green;
}
<div class="App">
<div class="AppMenu">
Menu
</div>
<div class="AppContainer">
Test
</div>
</div>
Last but not least. for HTML you have to use class not className which would be invalid HTML as this attribute doesnt exist.
These lines make no sense. This can be removed:
max-height: 100vh !important;
height: 100vh !important;
To stretch .AppContainer to the full free height, use rule flex: 1:
.AppContainer {
...
flex: 1;
}
And for the .App, set the flex rules. Like this:
.App {
...
display: flex;
flex-direction: column;
}
Flex has very good browser support.
Do you need such a result?
.App {
min-height: 100vh !important;
background-color: red;
display: flex;
flex-direction: column;
}
.AppMenu {
background-color: blue;
position: sticky;
top: 0px;
width: 100%;
font-size: 1.3em;
}
.AppContainer {
background-color: green;
flex: 1;
}
<div class="App">
<div class="AppMenu">
Menu
</div>
<div class="AppContainer">
Test
</div>
</div>

How to make an image fill a flex item with flex-grow?

I've read through all existing solutions in which images could fill the containing divs but I haven't found a solution for filling a div without a static dimension, such as divs that only have been laid out by flex-grow.
Currently the image will destroy the flex-grow proportions I have set on the container. I want the img to just fill the div and not stretch the div out.
As much as possible I don't want to inline style.
Is there an existing polyfill or solution to this?
.container {
display: flex;
min-height: 300px;
width: 500px;
flex: 1;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
.sub-container > div {
flex-grow: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background-color: yellow;
}
.second-container>img {
max-height: 100%;
max-width: 100%;
object-fit: scale-down;
}
<div class="container">
<div class="sub-container">
<div class="first-container">
A
</div>
<div class="second-container">
<img src="https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg" />
</div>
</div>
</div>
http://jsfiddle.net/jojonarte/tu3nbw4q/
You have this in your code:
.sub-container > div {
flex-grow: 1;
}
Okay, that defines flex-grow.
But you haven't defined flex-basis. As a result, flex-basis keeps its default value, which is: auto (i.e., content-defined).
That's what you're seeing your layout: A flex item that is being sized by the content.
In other words, because the natural dimensions of the image are so large (in comparison to the size of the container), the image is taking up all free space and flex-grow is having no effect (it has no free space to distribute).
As a solution, add this to the rule:
.sub-container > div {
flex-grow: 1;
flex-basis: 0; /* new */
}
or, more efficiently:
.sub-container > div {
flex: 1; /* fg:1, fs:1, fb:0 */
}
revised fiddle
.container {
display: flex;
min-height: 300px;
width: 500px;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
/* ADJUSTMENT HERE */
.sub-container > div {
flex: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background-color: yellow;
}
.second-container>img {
max-height: 100%;
max-width: 100%;
object-fit: scale-down;
}
<div class="container">
<div class="sub-container">
<div class="first-container">A</div>
<div class="second-container">
<img src="https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg" />
</div>
</div>
</div>
More information:
To avoid the problem described in the question, as a general rule, use the flex property instead of flex-grow, flex-shrink and flex-basis individually.
From the flexbox specification:
§ 7.2.1. Components of
Flexibility
Authors are encouraged to control flexibility using the flex
shorthand rather than with its longhand properties directly, as the
shorthand correctly resets any unspecified components to accommodate
common uses.
Learn more about the difference between flex-basis: auto and flex-basis: 0
Use background-image instead use img tag and use background-size: 100% 100%;:
See fiddle
.container {
display: flex;
min-height: 300px;
width: 500px;
flex: 1;
}
.sub-container {
flex: 1;
display: flex;
flex-direction: row;
}
.sub-container>div {
flex-grow: 1;
}
.first-container {
background-color: blue;
}
.second-container {
background: url(https://internationalbarcodes.net/wp-content/uploads/2017/04/QR%20code%20example.jpg);
background-repeat: no-repeat;
background-size: 100% 100%;
}
<div class="container">
<div class="sub-container">
<div class="first-container">
A
</div>
<div class="second-container">
</div>
</div>
</div>

Can't pull flexbox container to footer after page resize

After resizing of page nested content-box get down thru main div and break it.
It's look like so:
Here is live example (Content loading work on Chrome only). Here is jsfiddle
The css code that response for displaying problem (as I think) part:
.Central {
display: flex;
flex-direction: row;
flex-grow: 1;
height: auto;
}
.LeftSide {
background-color: #ddd0d1;
flex-grow: 8;
}
.RightSide{
background-color: #965254;
flex-grow: 1;
}
Instead of height: 100vh, use min-height: 100vh.
.MainContainer {
background-color: #fee9ea;
margin-left: 0%;
margin-right: 0%;
/* height: 100vh; <-- remove fixed height */
min-height: 100vh; /* new */
box-sizing: border-box;
display: flex;
flex-direction: column;
}
That will release your main container to expand with the content.
If you prefer the fixed height, then keep the height: 100vh and add vertical scroll:
.LeftSide {
background-color: #ddd0d1;
flex-grow: 8;
overflow: auto; /* new */
}

CSS: How to set procentual width using display:flex?

I have a requirement where I need to align content vertically within some divs. Flex-box would provide exactly what I need in an elegant way.
But I can't fully figure out whats the best way of setting the width of the flex-items is. If i use flex: 50%, the items grow with their content (which is not what I want). Also, I am not able to use overflow: hidden (because of the content within the divs).
Is it viable to set the width by using the good old width-property (this would work)? In other words: display: flex without flex: xx?
.wrapper {
display: flex;
width: 200px;
}
.left {
display: flex;
flex: 50%;
background-color: green;
/* overflow: hidden; *//* can't use that */
}
.right {
display: flex;
flex: 50%;
background-color: red;
/* overflow: hidden; *//* can't use that */
}
<div class="wrapper">
<div class="left">BigBigBigBigBig</div>
<div class="right">Small</div>
</div>
You can use flex: 0 0 50% so flex-grow will be set to 0 and it won't grow over 50%.
.wrapper {
display: flex;
width: 200px;
align-items: center;
}
.left {
flex: 0 0 50%;
background-color: green;
word-break: break-all;
}
.right {
flex: 0 0 50%;
background-color: red;
}
<div class="wrapper">
<div class="left">BigBigBsdfsdfigBigBigsdfsdf</div>
<div class="right">Small</div>
</div>
Does the fiddle supplied answer your question, just not too sure this is what you are after.

Height is not correct in flexbox items in Chrome [duplicate]

This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 6 years ago.
I've got a delicate problem for any CSS guru out there.
My green div has a flexible height, taking up the remaining.
And now I want to put a div inside that div which should be the half of the green div. But it seems like if Chrome treats it like half of the whole page rather than the flex item.
http://jsfiddle.net/unh5rw9t/1/
HTML
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>
CSS
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
}
#half_of_content {
height: 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
#Michael_B explained why Chrome behaves like this:
You gave the body a height: 100%. Then gave its child (.wrapper)
a height: 100%. Then gave its child (.content) a height: 100%.
So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be a 50% height
of body.
However, Firefox disagrees because, in fact, that height: 100% of .content is ignored and its height is calculated according to flex: 1.
That is, Chrome resolves the percentage with respect to the value of parent's height property. Firefox does it with respect to the resolved flexible height of the parent.
The right behavior is the Firefox's one. According to Definite and Indefinite Sizes,
If a percentage is going to be resolved against a flex item’s
main size, and the flex item has a definite flex
basis, and the flex container has a definite main
size, the flex item’s main size must be treated as
definite for the purpose of resolving the percentage, and the
percentage must resolve against the flexed main size of the
flex item (that is, after the layout algorithm below has been
completed for the flex item’s flex container, and the flex
item has acquired its final size).
Here is a workaround for Chrome:
#content {
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
height: auto;
}
This way the available space in #content will be distributed equally among #half_of_content and the ::after pseudo-element.
Assuming #content doesn't have other content, #half_of_content will be 50%. In your example you have a 2 in there, so it will be a bit less that 50%.
html,
body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
background-color: green;
display: flex;
flex-direction: column;
}
#content::after {
content: '';
flex: 1;
}
#half_of_content {
flex: 1;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
You could absolutely position div id="half_of_content".
#content {
flex: 1;
height: 100%;
background-color: green;
position: relative; /* new */
}
#half_of_content {
height: 50%;
background-color: yellow;
position: absolute; /* new */
width: 100%; /* new */
}
DEMO
With regard to your statement:
But it seems like if Chrome treats it like half of the whole page
rather than the flex item.
You gave the body a height: 100%. Then gave its child (.wrapper) a height: 100%. Then gave its child (.content) a height: 100%. So they're all equal height. Giving the next child (#half_of_content) a height: 50% would naturally be 50% height of body.
With absolute positioning, however, you don't need to specify parent heights.
Nesting flexboxes is a little buggy. I reworked your markup a little by adding an inner wrapper with display: flex; which seems to do the job. Here is the fiddle (also using class names instead of ids).
<div class="content">
<div class="wrapper-inner">
2
<div class="half">
2.1
</div>
</div>
</div>
.wrapper-inner {
position: absolute;
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
Fix:
on #content set
display: flex;
flex-flow: column nowrap;
justify-content: flex-end
on #half_of_content set flex: 0 0 50%;
Caveat: you need to add an extra div as a child of #content.
Here's the full example:
html,body {
height: 100%;
margin: 0;
}
#wrapper {
display: flex;
flex-flow: column;
height: 100%;
}
#menu {
height: 70px;
background-color: purple
}
#content {
flex: 1;
height: 100%;
display:flex;
flex-flow: column nowrap;
justify-content: flex-end;
background-color: green;
}
#half_of_content {
flex: 0 0 50%;
background-color: yellow;
}
#footer {
height: 100px;
background-color: cyan
}
<body>
<div id="wrapper">
<div id="menu">
1
</div>
<div id="content">2
<div id="half_of_content">2.1</div>
</div>
<div id="footer" style="">
3
</div>
</div>
</body>