I want to create a simple page with flex looks like this:
So this is what I try:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
}
.main {
background-color: green;
flex-grow: 1;
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>
My question is, when I set the height of the .header, there's a blank space between .header and the others. Anybody knows why? How can I fix it?
I know I can add more div to make it works, but I want a solution without adding any extra wrapper.
It seems that your content wrapped into two flex rows, and when height is distributed among those rows there are some extra space remained. All of that extra space is not given to last row automatically. So a gap remains unless you shrink the height of window to your contents' exact height.
If you want your second row to take remaining space using css, maybe you can assign remaining height to it with CSS like this:
.container {
height: 100vh;
display: flex;
flex-wrap: wrap;
}
.header {
height: 40px;
background-color: red;
width: 100%;
}
.sidenav {
background-color: blue;
align-items: flex-start;
height: calc(100vh - 40px);
}
.main {
background-color: green;
flex-grow: 1;
}
body
{
margin: 0
}
<div class="container">
<header class="header">Header</header>
<nav class="inner sidenav">Sidenav</nav>
<div class="inner main">Main</div>
</div>
Related
I have a container, in my case the body and html tags are the containers. And then I have 3 divs in them and I want the last one to fill the remaining vertical space available while still having a margin.
The third div is generated dynamically so I can't predict what height it's gonna need. The problem is, if it grows too much and a scrollbar is required, the bottom-margin it used to have goes away too. If a scrollbar is NOT required and doesn't appear, the margin is still there and everything looks like I want it to.
I tried to draw what I meant as best as I could in the above image. The 1st case is what I want to happen all the time, regardless of whether there's a scrollbar or not. The 2nd picture is what actually happens, the blue div loses its bottom margin, despite having it set.
Here's my CSS for the html and body tags (they contain the 3 divs, including the blue one):
html,
body
{
width: 100%;
height:100%;
margin: 0px;
padding: 0px;
display: flex;
flex-direction:column;
align-items: center;
background: #494d5f ;
}
and here's my code for the 3rd div, the blue one:
.bottomDiv
{
display:flex;
flex-direction:column;
background: #a0d2eb ;
align-items: center;
width: 97%;
margin-bottom:1.5%;
flex: 1 1 auto;
padding-top:1%;
padding-bottom:1%;
}
Maybe I didn't clarify well enough but the 3rd div in my case, the blue one grows just like it should, fully obeying its margins UNTIL a scrollbar appears and is needed. No matter the amount of growth it has to do, it does it perfectly while respecting its margin. But if it has to grow "out of bounds" of the page so to say, as in, a scrollbar is needed to display all the webpage then its margin is simply gone. IF there is NO scrollbar, everything looks perfect.
Just change this line: body { height: 100%; } to: body { min-height: 100vh; }.
With that line the body will have a height of at least the screen height (100vh) but allows i proper overflow as it is allowed to eb alrger then the screen. As such the margins wont get removed.
html,
body {
width: 100%;
min-height: 100vh;
margin: 0px;
padding: 0px;
display: flex;
flex-direction: column;
align-items: center;
background: #494d5f;
}
.topDiv,
.midDiv {
width: 97%;
height: 50px;
}
.topDiv {
margin-top: 1.5%;
background-color: red;
}
.midDiv {
background-color: blue;
}
.bottomDiv {
display: flex;
flex-direction: column;
background: #a0d2eb;
align-items: center;
width: 97%;
margin-bottom: 1.5%;
flex: 1 1 auto;
padding-top: 1%;
padding-bottom: 1%;
}
#height:checked + label::after {
content: "";
display: block;
height: 150vh;
}
<div class="topDiv"></div>
<div class="midDiv"></div>
<div class="bottomDiv">
<input type="checkbox" id="height" name="height">
<label for="height">checkmark me to extend box height</label>
</div>
I've put an example, so you may try this approach:
body,
html {
margin: 0;
padding: 0;
}
#page {
display: flex;
flex-direction: column;
height: 100vh;
outline: 1px solid purple;
}
#header {
height: 30px;
outline: 1px solid red;
}
#middle {
flex-grow: 1;
/* height: 100vh; */
/* flex-direction: column; */
outline: 1px solid green;
}
#footer {
outline: 1px solid blue;
}
<div id="page">
<div id="header">...</div>
<div id="middle">...</div>
<div id="footer">...</div>
</div>
Try to remove #footer and see that #middle fills the entire screen till the end.
In addition if you need any margins so you have to modify the container like this: #page { ..., margin: 10px; height: calc(100vh - 20px); }
I'd like to create a responsive page with a fixed html structure so I can just adjust the css. I would like to create rows with vertically and horizontally centered texts. The divs should fully stretch across the parent div.
My HTML...
<body>
<div class="parent">
<div class="d1">
one
</div>
<div class="d2">
two
</div>
<div class="d3">
three
</div>
</div>
</body>
My CSS...
body {
background-color: lightyellow;
height: 100%;
width: 100%;
margin: 0px;
}
.parent {
background-color: lightblue;
height: 100%;
}
.d1, .d2, .d3 {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 100px;
}
.d2 {
background-color: lightgreen;
}
However here I am setting d1, d2 and d3 to the height of 100px and not 100% of the parent div. Example here: https://jsfiddle.net/bLf2sxq0/
My second idea was to use display: table for the parent which results in table-rows for the childs but then I end up with the same stretching issue plus the texts are not vertically centered. Here the css would be like this ...
body {
background-color: lightyellow;
height: 100%;
width: 100%;
margin: 0px;
}
.parent {
width: 100%;
height: 100%;
display: table;
background-color: lightblue;
}
.d1, .d2, .d3 {
text-align: center;
height: 100px;
}
.d2 {
background-color: lightgreen;
}
Example here: https://jsfiddle.net/qmbzkwr2/
Is there a way to stretch the divs vertically along the parent and keep the texts centered vertically and horizontally within the divs? So I would not have width 100px but something like calc(100%/3) or any other solution to do this? Or maybe by using the flex grow option? Easiest way would do it :)
Thanks for any help!
You're on the right track. Use flexbox to stretch and fill items vertically and evenly. Remember to set parent containers (e.g. body, html) to height: 100%.
From here, if you want control over some items, use flex on any individual item, like flex: 1 1 300px on class .d2 for example.
Codepen
body, html {
height: 100%;
}
.parent {
background-color: lightblue;
height: 100%;
display: flex;
flex-direction: column;
}
.d1, .d2, .d3 {
display: flex;
align-items: center;
justify-content: center;
flex: 1;
}
.d2 {
background-color: lightgreen;
}
<div class="parent">
<div class="d1">
<div class="d11">
one
</div>
</div>
<div class="d2">
two
</div>
<div class="d3">
three
</div>
</div>
This question already has answers here:
Is it possible for flex items to align tightly to the items above them?
(5 answers)
Make a div span two rows in a grid
(2 answers)
Closed 5 years ago.
I have this structure ... it's similar to the WordPress administration area ... the point is that I need .main taking all the space available in width and height and .foot remains down while there is no content that lowers it. I want to use flex because I will have columns inside the .main and I need these columns take full height as well... Maybe someone can give me another solution, but I can NOT change the html, only the CSS
.wrap {
display: flex;
}
.sidebar {
position: fixed;
top: 0;
bottom: -100px;
background-color: #00a0d2;
width: 200px;
}
.main {
background-color: #66BB6A;
display: flex;
}
.foot {
margin-left: -200px;
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>
where the final result would be something like this, thx
A fixed position sidebar will not be affected by flexbox, so you need to adjust your margins to make room for it.
html,
body {
height: 100%;
}
body {
min-height: 100%;
}
.wrap {
display: flex;
flex-direction: column; /* required to establish column layout */
min-height: 100%;
}
.sidebar {
position: fixed;
top: 0;
bottom: 0; /* full height - change if required */
background-color: #00a0d2;
width: 200px;
opacity: .5/* for demo purposes */
;
}
.main {
background-color: #66BB6A;
display: flex;
flex: 1; /* take remaining height*/
margin-left: 200px; /* width of sidebar */
}
.foot {
margin-left: 200px; /* width of sidebar */
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>
You could use css grid. It allows room for 2d grid with minimal code.
.wrap {
display: grid;
/*Make 2 columns with the first having a min width of 200px*/
grid-template-columns: minmax(200px, 1fr) 10fr;
}
.sidebar {
background-color: #00a0d2;
/*Make sidebar take up the space of the 2 rows*/
grid-row: 1/3;
}
.main {
background-color: #66BB6A;
/*Let the main content take up the space of view height*/
height: 100vh;
}
.foot {
/*set footer to span the last row leaving the space for the sidebar*/
grid-column: 2/3;
background-color: #9999dd;
height: 60px;
}
<div class="wrap">
<div class="sidebar">Menu</div>
<div class="main">Content</div>
<div class="foot">Footer</div>
</div>
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>
I found several questions about but none of their solutions was working for me so here we go again.
Let's say I have this template of HTML
<html>
<div id="header">...</div>
<div id="contentA">...</div>
<div id="contentB">...</div>
<div id="footer">...</div>
</html>
The footer div should be at least 80px height, but if those 80px plus the height of all other 3 divs is not enough to fullfill the screen I want the footer to increase as much as the screen is filled with it below header, contentA and contentB.
BG-Color Solution
If you just want to let the remaining space have the same background-color as the footer (but not the body), you could add the footer bg-color to the html-tag:
html {
background-color: #footer_color;
}
body {
background-color: #body_color;
}
#footer {
min-height: 80px;
}
.
JS-Solution
If you have something more complex within your footer, you could use javascript/jquery to calculate the remaining space and set the footer to that height.
There is a similar question with a code example here: https://stackoverflow.com/a/14329340/3589841
.
Flexbox-Solution
If you only care about the latest browsers you can use the flexbox-box-model:
HTML:
<html>
<body>
<div id="flex_container">
<div id="header">...</div>
<div id="contentA">...</div>
<div id="contentB">...</div>
<div id="footer">...</div>
</div>
</body>
</html>
CSS:
html, body {
min-height: 100%;
}
#flex_container {
display: flex;
flex-direction: column;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: flex-start;
}
#header {
flex: 0 1 auto;
}
#contentA {
flex: 0 1 auto;
}
#contentB {
flex: 0 1 auto;
}
#footer {
flex: 0 1 100%;
min-height: 80px;
}
I believe you're going for something like this, have a look http://jsfiddle.net/dusUK/
Using CSS, we create a class, which in this case is fullheight, and we apply the following:
.fullheight {
display: block;
position: relative;
background: red;
height: 100%;
}
We also then apply the following to html, body
html, body {
height: 100%;
min-height: 100%;
}