I have a menu div that fills 100% of its container height, and beside it, to the right, are the header, body and footer sections.
I managed to do this with the CSS flex property. However, I want to change the amount of width the "menu" div takes out of the container, as in, making it 10% width of container's width, and make the rest divs fill what's left (even if the "menu" div is hidden at a later time).
JS Fiddle of what I have right now: https://jsfiddle.net/jf29vr0x/3/
.container {
display: flex;
flex-flow: column wrap;
width: 75%;
height: 500px;
position: relative;
margin: 0 auto;
}
.menu {
flex: 0 0 100%;
background: lightblue;
}
.header {
flex: 0 0 10%;
background: lightgray;
}
.body {
flex: 0 0 80%;
background: purple;
}
.footer {
flex: 0 0 10%;
background: lightgreen;
}
<div class="container">
<div class="menu">
Menu
</div>
<div class="header">
Header
</div>
<div class="body">
Body
</div>
<div class="footer">
Footer
</div>
</div>
I found that if I set the width explicitly on the "menu" class, it resizes it, but the rest of the boxes don't fill the space left, unless I also explicitly state their width to 100%. However, doing this, makes the container overflow, and because the container is aligned to the center, it looks off.
I could also set the width to 90% (on header, footer body) and 10% on the menu, but the menu is sometimes set to display: none;, so when it disappears, the other layout parts are only going to be 90% of container's width.
Is there any way of doing this with only flex-box properties? I don't understand very well what flex-shrink and flex-grow are about, but I think they only affect (in this case) the height?
Thank you.
You have to add a wrapper around the right column, and then only specify flex-basis on the .menu element.
.container {
display: flex;
width: 75%;
height: 500px;
position: relative;
margin: 0 auto;
height: 500px;
overflow: hidden;
}
.right-col {
flex-flow: column wrap;
flex-grow: 1;
height: 100%;
display: flex;
}
.menu {
flex-basis: 10%;
background: lightblue;
}
.header {
flex: 0 0 10%;
background: lightgray;
}
.body {
flex: 0 0 80%;
background: purple;
}
.footer {
flex: 0 0 10%;
background: lightgreen;
}
<div class="container">
<div class="menu">Menu</div>
<div class="right-col">
<div class="header">Header</div>
<div class="body">Body</div>
<div class="footer">Footer</div>
</div>
</div>
Fiddle: https://jsfiddle.net/jf29vr0x/11/
Now when the menu is hidden, the right column expands the full amount.
Related
In the following HTML, I want to set the height of left and right 100% of the parent element. In addition, the left div has fixed width. The right should use all of the remaining width.
I think because of using display: flex; in the parents div, the width of the left div doesn't stay constant. How can I set fixed width for it and allocate all of the remaining space to the right.
Edit: the calc(100-52px) is the height of the parent. The question is only about setting fixed width of 100px to the left so that it doesn't change on resizing the window.
Here's what I'm trying:
body {
padding: 0;
margin: 0;
}
.parent {
background: red;
display: flex;
height: calc(100vh - 52px);
}
.left {
width: 100px;
background: yellow;
}
.right {
background: orange;
width: 100%;
}
<div class="parent">
<div class="left">the width should be fixed, not flexible</div>
<div class="right">width should be all of the remaining</div>
</div>
parent { display: -webkit-box;display:-webkit-flex;display: -ms-flexbox;display:flex;flex-wrap: wrap; }
.parent > [class*='col-'] { display: flex; flex-direction: column; }
You can use width: calc(100% - 100px) or flex: 1 for the right div.
Percentage values are calculated from the parent element, therefore you need to extract static values from 100% to get the remaining area.
But as you are already using a flex container here, you can just set flex: 1, which is the shorthand for flex-grow: 1, that will allow your container to take all the extra space in the parent container, since no other items are available.
Add a flex declaration to the .left selector:
flex: 0 0 100px;
flex syntax:
none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
So this declaration is stating: "don't grow, don't shrink, define the initial size as 100px"
Read more: flex (MDN)
If right is to stand 52px away from the far right, then a margin will do . Please clarify your question.
body {
padding: 0;
margin: 0;
}
.parent {
background: red;
display: flex;
height: calc(100vh - 52px);
}
.left {
width: 100px;
background: yellow;
}
.right {
flex-grow: 1;
background: orange;
margin-right: 52px;
}
<div class="parent">
<div class="left">the width should be fixed, not flexible</div>
<div class="right">width should be all of the remaining</div>
</div>
Set flex: 0 0 100px; on your .left div (you can remove width: 100px) if you want it to be a constant 100px - so no growing or shrinking.
body {
padding: 0;
margin: 0;
}
.parent {
background: red;
display: flex;
height: calc(100vh - 52px);
}
.left {
flex: 0 0 100px;
background: yellow;
}
.right {
background: orange;
width: 100%;
}
<div class="parent">
<div class="left">the width should be fixed, not flexible</div>
<div class="right">width should be all of the remaining</div>
</div>
see if this helps you, comment if you need any changes
stackblits link for 1 fixed width, 1 relative column
I want to center .donut-graphs inside .dashboard horizontally, so the space between the right edge of the sidebar and the left edge of .donut-graphs is the same as the space from the right edge of .donut-graphs and the right edge of the screen. I have managed to do so, but I had to remove position: fixed from .navbar. The problem is, I can't do that because my sidebar has to stay on top of the screen when you scroll up/down, and with position: fixed on .navbar, the graphs aren't centered properly.
HTML:
<div class="container">
<div class="navbar">
</div>
<div class="content">
<div class="dashboard">
<div class="donut-graphs">
<div class="dashboard-income">
Div 1
</div>
<div class="dashboard-overall">
Div 2
</div>
<div class="dashboard-spent">
Div 3
</div>
</div>
</div>
</div>
</div>
CSS:
body {
margin: 0;
}
.container {
display: flex;
align-items: stretch;
max-width: 100%;
min-height: 100vh;
}
.navbar {
background-color: #ddd;
flex: 0 0 230px;
position: fixed;
height: 100vh;
width: 230px;
}
.content {
flex: 1;
overflow-x: auto;
text-align: center;
}
.donut-graphs {
display: inline-flex;
border: 1px solid;
margin: 50px auto 0;
position: relative;
text-align: left;
}
.dashboard-income,
.dashboard-overall,
.dashboard-spent {
height: 256px;
width: 357px;
display: inline-block;
}
.dashboard-income {
background-color: green;
}
.dashboard-overall {
background-color: blue;
}
.dashboard-spent {
background-color: red;
}
How can I overcome the issue?
Demo
position: fixed puts element above everything. That element won't attach to any element in body because it is the way that works. It only becomes dependent of viewport
What you want to achive could be done with position: absolute but parent (whose child you want to center) has to be position: relative for this to work.
Read more about positioning elements in css here
.content { padding-left:230px; }
Should do the trick.
Assigning your navbar a fixed position takes it out of the document flow, so when centering your donut graphs the browser doesn't take the navbar into account.
Giving the .content element a padding equivalent to the width of the navbar makes up for this.
The only problem with this approach is that if .navbar changes dimensions, you'll need to change the padding on .content to match.
In the below I have 2 div containers.
Container 1 which contains a google map div that looks like the below :
HTML
<div class="container">
<div class="mapCanvas2" #mapCanvas2></div>
</div>
CSS
.container{
height: 64%;
width: 100%;
}
.mapCanvas2{
position:relative;
height: 100%;
width: 100%;
}
Container 2
.container2{
height: 36%;
width: 100%;
}
The problem:
On some screens (depending on its height) a blank space shows up below container 2 to hide it I must set the height value of .container to 67% or above which is of course not a solution.
You can use flex, by specifing flex:1 you make the second container fill the remaining space :
body {
height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
}
.container {
height: 30%;
background: red;
}
.container-2 {
flex: 1;
background: blue;
}
<div class="container">
<div class="mapCanvas2" #mapCanvas2> map </div>
</div>
<div class="container-2"></div>
I have 2 divs that are placed on top of each other. For purposes of alignment, I am using display: flex and flex: column on the div containing these two divs. However, the first div uses the "height 0 padding" trick for videos. The problem I'm having, is that when using flex: column and change the width of the screen, the height doesn't change (and I want the height to change so that it matches the ratio for the video). What ends up happening is that the div stays the same, and the video shrinks within it and it looks ugly because there is extra background.
Plunker: https://plnkr.co/edit/TaeF5f8VufJWPU3GRZPr?p=preview
(in short, I want it such that when I change the width of the browser, the red div's height gets smaller)
CSS
/* Styles go here */
body {
height: 100%;
}
.container {
height: 80vh;
display: flex;
flex-flow: column;
}
.video {
flex: none;
height: 0;
padding-bottom: 30%;
background-color: red;
width: 80%;
}
.next-content {
flex: 1 0 auto;
width: 80%;
background-color: blue;
}
HTML:
<body>
<h1>Hello Plunker!</h1>
<div class="container">
<div class="video"></div>
<div class="next-content"></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>