I have a html layout like this:
,-------------.
|,-----------.|
|| child 1 ||
|`-----------'|
|,-----------.|
|| child 2 ||
|| ||
|| ||
|| ||
|| ||
|`-----------'|
`-------------'
The container is given a height value, say 100vh, and child 1 has a fixed height. I want the child 2 to automatically fill the remaining height.
I know there is a flexbox solution:
.container {
display: flex;
flex-direction: column;
}
.child-1 {
flex-shrink: 0;
flex-grow: 0;
}
.child-2 {
flex-grow: 1;
}
The solution works as alone, but if I want a third child child 3 inside child 2 with a height: 100%, it fails. I need to make child 2 flex and set child 3 to flex-grow: 1.
This kind of flex-inheriting become really frustrating as the nesting goes deeper. Also it violates "Seperation of Concern" since the DOM structure only works when all the nodes are properly set to display: flex.
Below is jsfiddle demonstrating the problem.
html,
body {
margin: 0;
}
div {
width: 100%;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
.child-1 {
height: 50px;
flex-shrink: 0;
flex-grow: 0;
}
.child-2 {
flex-grow: 1;
}
.child-3 {
height: 80%;
}
/* irrelevant styles like background-color etc. */
.container.irrelevant {
width: 100px;
background: green;
float: left;
margin-right: 20px;
}
.child-1.irrelevant {
background: red;
}
.child-2.irrelevant {
background: magenta;
}
.child-3.irrelevant {
background: yellow;
}
<div class="container irrelevant">
<div class="child-1 irrelevant">
Child 1
</div>
<div class="child-2 irrelevant">
Child 2<br> Seems like it works
</div>
</div>
<div class="container irrelevant">
<div class="child-1 irrelevant">
Child 1
</div>
<div class="child-2 irrelevant">
Child 2
<div class="child-3 irrelevant">
But it doesn't, child 3 should fill 80% height of the child 2.
</div>
</div>
</div>
Oh you can use calc for this. Something like this;
.child-2 { height: calc(100vh - 100px); }
Assuming the fixed height for .child-1 is 100px.
If you want something more dynamic use #patelarpan's solution, but this is quick and easy (and not dirty).
Add height: 100% to child 2.
you can use CSS grid also but it's not supported in all browsers.
html,
body {
margin: 0;
}
div {
width: 100%;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
.child-1 {
height: 50px;
flex-shrink: 0;
flex-grow: 0;
}
.child-2 {
flex-grow: 1;
height: calc(100% - 50px); /* add this line */
}
.child-3 {
height: 80%;
}
/* irrelevant styles like background-color etc. */
.container.irrelevant {
width: 100px;
background: green;
float: left;
margin-right: 20px;
}
.child-1.irrelevant {
background: red;
}
.child-2.irrelevant {
background: magenta;
}
.child-3.irrelevant {
background: yellow;
}
<div class="container irrelevant">
<div class="child-1 irrelevant">
Child 1
</div>
<div class="child-2 irrelevant">
Child 2<br> Seems like it works
</div>
</div>
<div class="container irrelevant">
<div class="child-1 irrelevant">
Child 1
</div>
<div class="child-2 irrelevant">
Child 2
<div class="child-3 irrelevant">
But it doesn't, child 3 should fill 80% height of the child 2.
</div>
</div>
</div>
It seems that .child-3 cannot properly calculate parents height unless it has set flex-basis. So you can fix this by using flex: 1 on child-2 DEMO or by just adding flex-basis: 0% DEMO which is the same thing that the browser will do if you use flex: 1.
html,
body {
margin: 0;
}
div {
width: 100%;
}
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
.child-1 {
flex: 1;
height: 50px;
flex-shrink: 0;
flex-grow: 0;
}
.child-2 {
flex: 1;
}
.child-3 {
height: 80%;
}
/* irrelevant styles like background-color etc. */
.container.irrelevant {
width: 100px;
background: green;
float: left;
margin-right: 20px;
}
.child-1.irrelevant {
background: red;
}
.child-2.irrelevant {
background: magenta;
}
.child-3.irrelevant {
background: yellow;
}
<div class="container irrelevant">
<div class="child-1 irrelevant">
Child 1
</div>
<div class="child-2 irrelevant">
Child 2<br> Seems like it works
</div>
</div>
<div class="container irrelevant">
<div class="child-1 irrelevant">
Child 1
</div>
<div class="child-2 irrelevant">
Child 2
<div class="child-3 irrelevant">
But it doesn't, child 3 should fill 80% height of the child 2.
</div>
</div>
</div>
Related
Imagine having this situation: a simple 3 rows layout made with flexbox, with the central row filling all the space available. Pretty standard stuff.
<body>
<div class="container">
<div class="flex-container">
<div>header</div>
<div class="content">
<div class="item red">asdasd</div>
<div class="item yellow">asdasd</div>
<div class="item green">asdasd</div>
</div>
<div>footer</div>
</div>
<div>
<body>
Here the CSS:
html,
body,
.container {
height: 100%;
}
.flex-container {
height: 100%;
display: flex;
flex-direction: column;
}
.flex-container .content {
flex: 1;
}
.flex-container .content .item {
height: 100%;
}
(omitting css for background colors, you can guess it).
The problem is that the "content" div does not push down the footer div, keeping it at the bottom of the page, like is position:fixed with bottom: 0.
Scrolling the page show, except for this problem, the correct behavior, with 3 div with different color all sizing 100% the browser window.
What I'm missing?
EDIT: look at this jsfiddle
https://jsfiddle.net/rq1xywng/
I am not sure about what you are looking for. May be it will be help for you.
html,
body {
margin: 0;
padding: 0;
box-sizing: border-box;
height: 100vh;
min-height: 100vh;
}
.container {
height: 100vh;
min-height: 100vh;
background-color: fuchsia;
}
.header, .footer {
height: 30px;
}
.flex-container .content {
display: flex;
height: 100%;
height: calc(100vh - 60px);
}
.flex-container .content .item {
width: 100%;
height: 100%;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.green {
background-color: green;
}
<div class="container">
<div class="flex-container">
<div class="header">header</div>
<div class="content">
<div class="item red">asdasd</div>
<div class="item yellow">asdasd</div>
<div class="item green">asdasd</div>
</div>
<div class="footer">footer</div>
</div>
<div>
So you have couple of errors here:
you set EVERY ITEM IN THE CONTAINER to be 100% - this amounts to 300% :)
their parent is "only" 100%
footer will be hidden unless given height
you used vh and % combined in an unhealthy way.
you should have 2 flex components:
.flex-container - to match to screen size
.flex-container .content - to be able to stretch the items
You should set .item to flex: 1;
Here is a working version: https://jsfiddle.net/oj0thmv7/5/
Here is a working example with scroll: https://jsfiddle.net/oyLbxsrc/
If you change the 100% to 100vh this works
.flex-container .content .item {
height: 100vh;
}
Or have I misunderstood the issue?
This question already has answers here:
Chrome / Safari not filling 100% height of flex parent
(5 answers)
Closed 3 years ago.
In Chrome, Edge, and FireFox, the below code produces the (correct) output where the innermost div fills it's parent using min-height: 100%. However, in Safari this does not occur. I expect the green div to be completely covered by its children.
Why is that? / How can I obtain the correct behavior?
.container {
display: flex;
flex-direction: column;
height: 80vh;
}
.item1 {
flex-shrink: 0;
background: red;
}
.item2 {
flex-grow: 1;
background: green;
}
.inner {
background: blue;
min-height: 100%;
}
<div class="container">
<div class="item1">Random text for size</div>
<div class="item2">
<div class="inner"></div>
</div>
</div>
StackBlitz
This can be fixed by setting an explicit height for every parent element of .inner.
<div class="container">
<div class="item1">Random text for size</div>
<div class="item2">
<div class="inner"></div>
</div>
</div>
<style>
.container {
display: flex;
flex-direction: column;
height: 80vh;
}
.item1 {
flex-shrink: 0;
background: red;
}
.item2 {
flex-grow: 1;
height: 100%;
background: green;
}
.inner {
background: blue;
min-height: 100%;
}
</style>
Background info and more possible fixes: Chrome / Safari not filling 100% height of flex parent
So I have a problem where I have 2 divs inside of another div with a fixed size. I the second of the two is too large to fit in the fixed height div so I want a scroll bara to appear. But the scrollbar goes outside of the content. How do I fix this?
html:
<div class="main">
<div class="first-child">
<div class="small-content">
Content
</div>
</div>
<div class="second-child">
<div class="large-content">
Content
</div>
</div>
</div>
css:
.main {
height: 250px;
overflow: hidden;
}
.first-child {
background-color: red;
}
.second-child {
max-height: 100%;
background-color: blue;
overflow-y: scroll;
}
.large-content {
padding-top: 300px;
}
.small-content {
padding: 10px;
}
https://codepen.io/RilleJ/pen/JeBVpz
I added an example as well to show what I mean. Basically I want to be able to scroll all the way down in the blue box and see the content without setting a fixed height. (Not that the content above, the red box, can be different sizes)
Use flexbox to divide the space of the container among the children.
Add flex-grow: 0, and flex-shrink: 0 for a child that just needs to take the space it needs for its content.
Add flex-grow: 1, and flex-shrink: 1 on the other children to divide the remaining space equally (each child will take at least the size of its content).
.main {
height: 250px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.first-child {
flex-grow: 0;
flex-shrink: 0;
background-color: red;
}
.second-child {
flex-grow: 1;
flex-shrink: 1;
background-color: blue;
overflow-y: scroll;
}
.large-content {
padding-top: 300px;
}
.small-content {
padding: 10px;
}
<div class="main">
<div class="first-child">
<div class="small-content">
Content
</div>
</div>
<div class="second-child">
<div class="large-content">
Content
</div>
</div>
</div>
Refer to this Fiddle.
I have a top-level div whose height is configured as one screen height (height:100vh). Within this div, there is a fixed-height (60px) child div and another child div I want to grow to fill the remaining height (so as to be responsive with different screen sizes).
This child div has an image and some text. Currently, its width is hard-coded, or else the image fills the entire screen (and exceeds the length of its parent). Setting height:100% (or even calc(100% - 60px)) doesn't scale the div as I'd hoped.
.one-page {
min-height: 100vh;
max-height: 100vh;
background-color: #FF5555;
}
.fixed-size {
height: 60px;
border-style: solid;
}
.main-container {
background-color: #55FF55;
width: 300px;
margin: auto;
}
.subtitle {
text-align: center
}
.other {
background-color: blue;
}
img {
vertical-align: middle;
width: 100%;
height: auto;
}
<body>
<div class="one-page">
<div class="fixed-size">
this div is a fixed size
</div>
<div class="main-container">
<p>
<img src="http://images.clipartpanda.com/square-clip-art-clipart-square-shield-256x256-e296.png">
</p>
<div class="subtitle">
subtitle text
</div>
</div>
</div>
<div class="other">
something else
</div>
</body>
Try to use height:calc(100vh - 60px).
.main-container {
background-color: #ff00ff;
width: 300px;
margin: auto;
padding:0;
height:calc(100vh - 60px);
}
DEMO
Use flexbox to work it out. Run the below snippet and you'll understand. flex-grow: 1 will basically give all the remaining height to the second child.
.p {
height: 100vh;
display: flex;
flex-direction: column;
}
.c1 {
height: 60px;
background-color: green;
}
.c2 {
flex-grow: 1;
background-color: red;
}
<div class="p">
<div class="c1"></div>
<div class="c2"></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 am trying to have one div on the left and two on the right. The bottomright should always be below the topRight div. The topRight is the only div with a variable height.
I am currently trying to achieve this using flexbox als you can see in my code below.
I would like to have some directions.
.wrapper {
display: flex;
height: 100px;
}
.left {
background-color: green
}
.topRight {
background-color: yellow
}
.bottomright {
background-color: red
}
<div class="wrapper">
<div class="left">Left</div>
<div class="topRight">TopRight</div>
<div class="bottomright">Bottom</div>
</div
With a fixed height on the container, as you have in your code, you can use flex-direction: column and flex-wrap: wrap. The fixed height serves as a break point, telling flex items where to wrap.
.wrapper {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 100px;
}
.left {
flex: 0 0 100%; /* consumes full height of first column; forces siblings to wrap */
background-color: lightgreen
}
/* variable height div */
.topRight {
background-color: yellow
}
.bottomright {
flex: 1; /* consumes remaining space in column */
background-color: red
}
<div class="wrapper">
<div class="left">Left</div>
<div class="topRight">TopRight<br>variable height</div>
<div class="bottomright">Bottom</div>
</div>
On html put a div with a class called right wrapping both topRight and bottomRight and use this css on css:
.wrapper {
display: flex;
height: 100px;
}
.right {
display: flex-flow;
}
.left {
background-color: green
}
.topRight {
background-color: yellow;
height: 50px;
}
.bottomright {
background-color: red;
height: 50px;
}
I hope that helps you :)
For infos
display:grid is made for this .... very soon available for most browsers and yet for a few
A tutorial among others : https://css-tricks.com/snippets/css/complete-guide-grid/
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
/* any height s */
background-color: green;
}
.leftspan {
grid-row: span 2;/* if 2 rows avalaible */
}
.topRight {
background-color: yellow;
grid-column: 2 /-1
}
.bottomright {
background-color: red;
grid-column: 2 /-1
}
.bottomfull {
background-color: red;
grid-column: 1 /-1
}
<div class="wrapper">
<div class="leftspan">Left spanning 2 rows</div>
<div class="topRight">Top <br/>Right</div>
<div class="bottomright">Bottom <br/>Right</div>
</div>
<p> or did you mean ?
<div class="wrapper">
<div class="left">Left</div>
<div class="topRight">Top Right</div>
<div class="bottomfull">Bottom <br/>Right</div>
</div>
render if your browsers understand grid: