How to make that a column using flexbox has a height which automatically/dynamically matches its width?
#container { display: flex; width: 500px; flex-direction: row; }
#a { background-color: red; width: 50%; }
#b { background-color: blue; width: 50%; height: 50%; }
<div id="container">
<div id="a">
Hello
</div>
<div id="b">
This div should be square, its height should automatically match its width, and text vertically centered
</div>
</div>
Note: I don't want to use the aspect-ratio property which is too young (not support on enough browsers for my project) nor the similar solutions of Maintain the aspect ratio of a div with CSS, but with flexbox, as mentioned on top. Also this linked question does not consider the vertical alignement either.
Related
The following does exactly what I want, but I don't understand why, which annoys me.
I want:
the "second" div to take as much space as it can, within the constraints of its parent
then divide that space evenly amongst it's 2 child divs
scale the imgs so that they fit exactly in their parent div
<!DOCTYPE html>
<html>
<head>
<style>
.root {
width: 500px;
height: 500px;
}
.flex-container {
display: flex;
flex-direction: column;
background-color: red;
height: 100%;
width: 100%;
}
.first {
background-color: blue;
}
.second {
background-color: darkmagenta;
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.wrap {
height: 50%;
width: 100%;
}
img {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div class="root">
<div class="flex-container">
<div class="first">
This div should be sized accoring to it's content and wrap if needed
which it does, nice!
</div>
<div class="second">
<div class="wrap">
<img
src="https://www.publicdomainpictures.net/pictures/30000/velka/cat-13476279941Ls.jpg"
/>
</div>
<div class="wrap">
<img
src="https://www.publicdomainpictures.net/pictures/30000/velka/cat-13476279941Ls.jpg"
/>
</div>
</div>
</div>
</div>
</body>
</html>
After experimenting and messing around I arrived at this HTML and CSS. Crucial is the overflow: hidden; on the "second" div. Without it, the child imgs are displayed larger, growing the "second" div beyond its parent.
I do not understand how overflow: hidden; can affect the size of the childs - I would have expected them to be clipped. Any pointers?
I found a nicer way to do this in this post: flex child is growing out of parent
Instead of putting overflow: hidden; on the parent, that posts suggest setting min-height: 0; which allows its children to shrink and become smaller than their content.
That makes more sense to me.
EDIT
Found this post with even more detail, and a link to the flexbox spec which explains it all: Why don't flex items shrink past content size?
On a flex item whose overflow is visible in the main axis, when specified on the flex item’s main-axis min-size property, specifies an automatic minimum size. It otherwise computes to 0.
Consider the following HTML/css code sample:
<div id="container">
<div id="up">Text<br />Text<br />Text<br /></div>
<div id="down">Text<br />Text<br />Text<br /></div>
</div>
#container { width: 300px; height: 300px; border:1px solid red;}
#up { background: green; }
#down { background:pink;}
where I have a container div with two children (also here: http://jsfiddle.net/S8g4E/). The first child has a given height. How can I make the second child to occupy the "free space" of the container div without giving a specific height?
In the example, the pink div should occupy also the white space.
Similar to this question: How to make div occupy remaining height?
But I don't want to give position absolute.
Expanding the #down child to fill the remaining space of #container can be accomplished in various ways depending on the browser support you wish to achieve and whether or not #up has a defined height.
Samples
.container {
width: 100px;
height: 300px;
border: 1px solid red;
float: left;
}
.up {
background: green;
}
.down {
background: pink;
}
.grid.container {
display: grid;
grid-template-rows: 100px;
}
.flexbox.container {
display: flex;
flex-direction: column;
}
.flexbox.container .down {
flex-grow: 1;
}
.calc .up {
height: 100px;
}
.calc .down {
height: calc(100% - 100px);
}
.overflow.container {
overflow: hidden;
}
.overflow .down {
height: 100%;
}
<div class="grid container">
<div class="up">grid
<br />grid
<br />grid
<br />
</div>
<div class="down">grid
<br />grid
<br />grid
<br />
</div>
</div>
<div class="flexbox container">
<div class="up">flexbox
<br />flexbox
<br />flexbox
<br />
</div>
<div class="down">flexbox
<br />flexbox
<br />flexbox
<br />
</div>
</div>
<div class="calc container">
<div class="up">calc
<br />calc
<br />calc
<br />
</div>
<div class="down">calc
<br />calc
<br />calc
<br />
</div>
</div>
<div class="overflow container">
<div class="up">overflow
<br />overflow
<br />overflow
<br />
</div>
<div class="down">overflow
<br />overflow
<br />overflow
<br />
</div>
</div>
Grid
CSS's grid layout offers yet another option, though it may not be as straightforward as the Flexbox model. However, it only requires styling the container element:
.container { display: grid; grid-template-rows: 100px }
The grid-template-rows defines the first row as a fixed 100px height, and the remain rows will automatically stretch to fill the remaining space.
I'm pretty sure IE11 requires -ms- prefixes, so make sure to validate the functionality in the browsers you wish to support.
Flexbox
CSS3's Flexible Box Layout Module (flexbox) is now well-supported and can be very easy to implement. Because it is flexible, it even works when #up does not have a defined height.
#container { display: flex; flex-direction: column; }
#down { flex-grow: 1; }
It's important to note that IE10 & IE11 support for some flexbox properties can be buggy, and IE9 or below has no support at all.
Calculated Height
Another easy solution is to use the CSS3 calc functional unit, as Alvaro points out in his answer, but it requires the height of the first child to be a known value:
#up { height: 100px; }
#down { height: calc( 100% - 100px ); }
It is pretty widely supported, with the only notable exceptions being <= IE8 or Safari 5 (no support) and IE9 (partial support). Some other issues include using calc in conjunction with transform or box-shadow, so be sure to test in multiple browsers if that is of concern to you.
Other Alternatives
If older support is needed, you could add height:100%; to #down will make the pink div full height, with one caveat. It will cause overflow for the container, because #up is pushing it down.
Therefore, you could add overflow: hidden; to the container to fix that.
Alternatively, if the height of #up is fixed, you could position it absolutely within the container, and add a padding-top to #down.
And, yet another option would be to use a table display:
#container { width: 300px; height: 300px; border: 1px solid red; display: table;}
#up { background: green; display: table-row; height: 0; }
#down { background: pink; display: table-row;}
Its been almost two years since I asked this question. I just came up with css calc() that resolves this issue I had and thought it would be nice to add it in case someone has the same problem. (By the way I ended up using position absolute).
http://jsfiddle.net/S8g4E/955/
Here is the css
#up { height:80px;}
#down {
height: calc(100% - 80px);//The upper div needs to have a fixed height, 80px in this case.
}
And more information about it here: http://css-tricks.com/a-couple-of-use-cases-for-calc/
Browser support: http://caniuse.com/#feat=calc
Abstract
I didn't find a fully satisfying answer so I had to find it out myself.
My requirements:
the element should take exactly the remaining space either when its content size is smaller or bigger than the remaining space size (in the second case scrollbar should be shown);
the solution should work when the parent height is computed, and not specified;
calc() should not be used as the remaining element shouldn't know anything about another element sizes;
modern and familar layout technique such as flexboxes should be used.
The solution
Turn into flexboxes all direct parents with computed height (if any) and the next parent whose height is specified;
Specify flex-grow: 1 to all direct parents with computed height (if any) and the element so they will take up all remaining space when the element content size is smaller;
Specify flex-shrink: 0 to all flex items with fixed height so they won't become smaller when the element content size is bigger than the remaining space size;
Specify overflow: hidden to all direct parents with computed height (if any) to disable scrolling and forbid displaying overflow content;
Specify overflow: auto to the element to enable scrolling inside it.
JSFiddle (element has direct parents with computed height)
JSFiddle (simple case: no direct parents with computed height)
My answer uses only CSS, and it does not use overflow:hidden or display:table-row. It requires that the first child really does have a given height, but in your question you state that only the second child need have its height not specified, so I believe you should find this acceptable.
#container {
width: 300px;
height: 300px;
border: 1px solid red;
}
#up {
background: green;
height: 63px;
float: left;
width: 100%
}
#down {
background: pink;
padding-top: 63px;
height: 100%;
box-sizing: border-box;
}
<div id="container">
<div id="up">Text<br />Text<br />Text<br /></div>
<div id="down">Text<br />Text<br />Text<br /></div>
</div>
check the demo - http://jsfiddle.net/S8g4E/6/
use css -
#container { width: 300px; height: 300px; border:1px solid red; display: table;}
#up { background: green; display: table-row; }
#down { background:pink; display: table-row;}
Unless I am misunderstanding, you can just add height: 100%; and overflow:hidden; to #down.
#down {
background:pink;
height:100%;
overflow:hidden;
}
Live DEMO
Edit: Since you do not want to use overflow:hidden;, you can use display: table; for this scenario; however, it is not supported prior to IE 8. (display: table; support)
#container {
width: 300px;
height: 300px;
border:1px solid red;
display:table;
}
#up {
background: green;
display:table-row;
height:0;
}
#down {
background:pink;
display:table-row;
}
Live DEMO
Note: You have said that you want the #down height to be #container height minus #up height. The display:table; solution does exactly that and this jsfiddle will portray that pretty clearly.
You can use floats for pushing content down:
http://jsfiddle.net/S8g4E/5/
You have a fixed size container:
#container {
width: 300px; height: 300px;
}
Content is allowed to flow next to a float. Unless we set the float to full width:
#up {
float: left;
width: 100%;
}
While #up and #down share the top position, #down's content can only start after the bottom of the floated #up:
#down {
height:100%;
}
<div class='parent'>
<div class='child'>
<div class='child last'>
</div>
<style>
.parent {
display: flex;
flex-direction: column;
.child {
&.last {
flex-grow: 1;
}
}
}
</style>
I'm not sure it can be done purely with CSS, unless you're comfortable in sort of faking it with illusions. Maybe use Josh Mein's answer, and set #container to overflow:hidden.
For what it's worth, here's a jQuery solution:
var contH = $('#container').height(),
upH = $('#up').height();
$('#down').css('height' , contH - upH);
I need to create a 2 rows layout for a web page to manage a section for filters and other section for results with the following characteristics:
the page cannot overflow the height of 100%
the height of the first row is based on his content (could be variable and a javascript function can change it by hiding some elements)
the height of the second row is the difference between 100% and the height of first row
in the second row the div with overflow must be the one with class "list" and I can't move it to div with class="result" (that will make it work)
HTML:
<div class="main">
<div class="filter">
<div class="filtercontent">
filter content
</div>
</div>
<div class="result">
<div class="resultcontent">
<div class="list">
<div class="listcontent">
list content
</div>
</div>
</div>
</div>
</div>
CSS:
.main {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.filter {
width: 100%;
}
.result {
width: 100%;
}
.resultcontent {
height: 100%;
width: 100%;
}
.list {
height: 100%;
width: 100%;
overflow: auto;
}
.listcontent {
height: 1000px;
width: 2000px;
}
I tried with flexbox (in different ways) but I can't find a solution for the last point.
IMPORTANT: I can't use javascript to set the height of the rows. I need a solution using only CSS.
Thanks!
If you declare your .result div with "flex: 1" property it will take all space remaining in the outer div (.main). So if the .filter div occupies 500 height pixels the .result will adjust in the blank space filling the 100% from the parent. If you change it dynamically hiding or adding elements flex: 1 will guarantee that all remaining space will be populated by .result automatically.
Hope it helps
I'm trying to achieve a certain fluid layout where the content of each DIVs are centered vertically and horizontally. But, my middle row (A, B, C) keeps on having vertical and/or horizontal alignment issues.
The goal is to have it work like this:
Note: If there's a way I can have the option to set the Mobile layout's "C" area fluid as well (without having to change the HTML, just the CSS, so that I can test which option works best), that'd be a bonus!
Here's a snippet of the HTML:
<div class="page">
<div class="col col-top">top</div>
<div class="col col-mid">
<div class="col col-left">
<div class="centerBox"><div class='debugBox'></div></div>
</div>
<div class="col col-center">
<div class="centerBox"><div class='debugBox'></div></div>
</div>
<div class="col col-right">
<div class="centerBox"><div class='debugBox'></div></div>
</div>
</div>
<div class="col col-bottom">bottom</div>
</div>
I'm not sure if the "wrapper" DIVs with the "centerBox" class is really necessary (they're set as display: table-cell while each col class are set to display: table to behave like tables, but this causes issues to place those areas with position: absolute and % values for their left / right / top / bottom properties.
For instance, if the "C" area is set to display: table, this happens:
And if I change the "C" area to display: block;, then it fills that full center area, but...
... the horizontal and vertical alignment breaks inside of it.
Would using "Ghost" DIV elements (as discussed in this css-tricks article, "Centering in the Unknown" by Chris Coyier ) be any better to get the correct alignment?
Ok, this solution works without a framework, pure CSS using flexbox. As long as the layout is horizontal, C has a fixed width. When it is mobile, C takes up the whole width and has a variable height.
header,
footer {
padding: 10px;
background-color: lightblue;
}
main {
display: flex;
flex-direction: row;
}
main > div {
padding: 10px;
background-color: tomato;
flex-grow: 1;
min-height: 40px;
display: flex;
align-items: center;
}
main > div:nth-child(2) {
background-color: olive;
}
.fixed {
width: 400px;
}
#media (max-width: 768px) {
main {
flex-direction: column;
}
.fixed {
width: auto;
}
}
<header>Top</header>
<main>
<div>A</div>
<div class="fixed">C</div>
<div>B</div>
</main>
<footer>Bottom</footer>
Here is a pen (drag the border to see the mobile layout):
Codepen
Here are the styles for the code you have provided. The one thing to keep in mind is your middle column, being a fixed width, is what helps with the calc() function. 50% of HALF the width of the middle container. This will not work in IE 8 or less, so you'll have to write a JS solution if you care about those browsers.
.page {
width: 100%;
position: relative;
}
.col-top {
background: #0f0;
width: 100%;
height: 50px;
}
.page .col-mid {
width: 100%;
display: table;
}
.page .col-mid .col {
width: calc(50% - 250px);;
height: 100px;
background: #f00;
display: table-cell;
vertical-align: middle;
text-align: center;
}
.page .col-mid .col-center {
width: 500px;
background: #00f;
}
.debugBox {
display: inline-block;
width: 20px;
height: 20px;
background: #000;
vertical-align: middle;
}
.col-bottom {
clear: both;
height: 50px;
background: #0f0;
}
and a working example here:
https://jsfiddle.net/g45pwedd/
And you don't need some of the container elements, as you stated.
UPDATE
Sorry, forgot to add for responsive. I wasn't sure if you still needed vertical align for responsive or not. This solution removes vertical align, as I doubt it's needed on a mobile display anyways:
#media (max-width: 768px) {
.page .col-mid .col {
display: block;
width: 100%;
}
}
https://jsfiddle.net/g45pwedd/2/
In bootstrap 4
to center the childs horizontally, use bootstrap-4 class
justify-content-center
to center the childs vertically, use bootstrap-4 class
align-items-center
but remember don't forget to use d-flex class with these
it's a bootstrap-4 utility class, like so
<div class="d-flex justify-content-center align-items-center" style="height:100px;">
<span class="bg-primary">MIDDLE</span>
</div>
Note: make sure to add bootstrap-4 utilities if this code does not work
Consider the following HTML/css code sample:
<div id="container">
<div id="up">Text<br />Text<br />Text<br /></div>
<div id="down">Text<br />Text<br />Text<br /></div>
</div>
#container { width: 300px; height: 300px; border:1px solid red;}
#up { background: green; }
#down { background:pink;}
where I have a container div with two children (also here: http://jsfiddle.net/S8g4E/). The first child has a given height. How can I make the second child to occupy the "free space" of the container div without giving a specific height?
In the example, the pink div should occupy also the white space.
Similar to this question: How to make div occupy remaining height?
But I don't want to give position absolute.
Expanding the #down child to fill the remaining space of #container can be accomplished in various ways depending on the browser support you wish to achieve and whether or not #up has a defined height.
Samples
.container {
width: 100px;
height: 300px;
border: 1px solid red;
float: left;
}
.up {
background: green;
}
.down {
background: pink;
}
.grid.container {
display: grid;
grid-template-rows: 100px;
}
.flexbox.container {
display: flex;
flex-direction: column;
}
.flexbox.container .down {
flex-grow: 1;
}
.calc .up {
height: 100px;
}
.calc .down {
height: calc(100% - 100px);
}
.overflow.container {
overflow: hidden;
}
.overflow .down {
height: 100%;
}
<div class="grid container">
<div class="up">grid
<br />grid
<br />grid
<br />
</div>
<div class="down">grid
<br />grid
<br />grid
<br />
</div>
</div>
<div class="flexbox container">
<div class="up">flexbox
<br />flexbox
<br />flexbox
<br />
</div>
<div class="down">flexbox
<br />flexbox
<br />flexbox
<br />
</div>
</div>
<div class="calc container">
<div class="up">calc
<br />calc
<br />calc
<br />
</div>
<div class="down">calc
<br />calc
<br />calc
<br />
</div>
</div>
<div class="overflow container">
<div class="up">overflow
<br />overflow
<br />overflow
<br />
</div>
<div class="down">overflow
<br />overflow
<br />overflow
<br />
</div>
</div>
Grid
CSS's grid layout offers yet another option, though it may not be as straightforward as the Flexbox model. However, it only requires styling the container element:
.container { display: grid; grid-template-rows: 100px }
The grid-template-rows defines the first row as a fixed 100px height, and the remain rows will automatically stretch to fill the remaining space.
I'm pretty sure IE11 requires -ms- prefixes, so make sure to validate the functionality in the browsers you wish to support.
Flexbox
CSS3's Flexible Box Layout Module (flexbox) is now well-supported and can be very easy to implement. Because it is flexible, it even works when #up does not have a defined height.
#container { display: flex; flex-direction: column; }
#down { flex-grow: 1; }
It's important to note that IE10 & IE11 support for some flexbox properties can be buggy, and IE9 or below has no support at all.
Calculated Height
Another easy solution is to use the CSS3 calc functional unit, as Alvaro points out in his answer, but it requires the height of the first child to be a known value:
#up { height: 100px; }
#down { height: calc( 100% - 100px ); }
It is pretty widely supported, with the only notable exceptions being <= IE8 or Safari 5 (no support) and IE9 (partial support). Some other issues include using calc in conjunction with transform or box-shadow, so be sure to test in multiple browsers if that is of concern to you.
Other Alternatives
If older support is needed, you could add height:100%; to #down will make the pink div full height, with one caveat. It will cause overflow for the container, because #up is pushing it down.
Therefore, you could add overflow: hidden; to the container to fix that.
Alternatively, if the height of #up is fixed, you could position it absolutely within the container, and add a padding-top to #down.
And, yet another option would be to use a table display:
#container { width: 300px; height: 300px; border: 1px solid red; display: table;}
#up { background: green; display: table-row; height: 0; }
#down { background: pink; display: table-row;}
Its been almost two years since I asked this question. I just came up with css calc() that resolves this issue I had and thought it would be nice to add it in case someone has the same problem. (By the way I ended up using position absolute).
http://jsfiddle.net/S8g4E/955/
Here is the css
#up { height:80px;}
#down {
height: calc(100% - 80px);//The upper div needs to have a fixed height, 80px in this case.
}
And more information about it here: http://css-tricks.com/a-couple-of-use-cases-for-calc/
Browser support: http://caniuse.com/#feat=calc
Abstract
I didn't find a fully satisfying answer so I had to find it out myself.
My requirements:
the element should take exactly the remaining space either when its content size is smaller or bigger than the remaining space size (in the second case scrollbar should be shown);
the solution should work when the parent height is computed, and not specified;
calc() should not be used as the remaining element shouldn't know anything about another element sizes;
modern and familar layout technique such as flexboxes should be used.
The solution
Turn into flexboxes all direct parents with computed height (if any) and the next parent whose height is specified;
Specify flex-grow: 1 to all direct parents with computed height (if any) and the element so they will take up all remaining space when the element content size is smaller;
Specify flex-shrink: 0 to all flex items with fixed height so they won't become smaller when the element content size is bigger than the remaining space size;
Specify overflow: hidden to all direct parents with computed height (if any) to disable scrolling and forbid displaying overflow content;
Specify overflow: auto to the element to enable scrolling inside it.
JSFiddle (element has direct parents with computed height)
JSFiddle (simple case: no direct parents with computed height)
My answer uses only CSS, and it does not use overflow:hidden or display:table-row. It requires that the first child really does have a given height, but in your question you state that only the second child need have its height not specified, so I believe you should find this acceptable.
#container {
width: 300px;
height: 300px;
border: 1px solid red;
}
#up {
background: green;
height: 63px;
float: left;
width: 100%
}
#down {
background: pink;
padding-top: 63px;
height: 100%;
box-sizing: border-box;
}
<div id="container">
<div id="up">Text<br />Text<br />Text<br /></div>
<div id="down">Text<br />Text<br />Text<br /></div>
</div>
check the demo - http://jsfiddle.net/S8g4E/6/
use css -
#container { width: 300px; height: 300px; border:1px solid red; display: table;}
#up { background: green; display: table-row; }
#down { background:pink; display: table-row;}
Unless I am misunderstanding, you can just add height: 100%; and overflow:hidden; to #down.
#down {
background:pink;
height:100%;
overflow:hidden;
}
Live DEMO
Edit: Since you do not want to use overflow:hidden;, you can use display: table; for this scenario; however, it is not supported prior to IE 8. (display: table; support)
#container {
width: 300px;
height: 300px;
border:1px solid red;
display:table;
}
#up {
background: green;
display:table-row;
height:0;
}
#down {
background:pink;
display:table-row;
}
Live DEMO
Note: You have said that you want the #down height to be #container height minus #up height. The display:table; solution does exactly that and this jsfiddle will portray that pretty clearly.
You can use floats for pushing content down:
http://jsfiddle.net/S8g4E/5/
You have a fixed size container:
#container {
width: 300px; height: 300px;
}
Content is allowed to flow next to a float. Unless we set the float to full width:
#up {
float: left;
width: 100%;
}
While #up and #down share the top position, #down's content can only start after the bottom of the floated #up:
#down {
height:100%;
}
<div class='parent'>
<div class='child'>
<div class='child last'>
</div>
<style>
.parent {
display: flex;
flex-direction: column;
.child {
&.last {
flex-grow: 1;
}
}
}
</style>
I'm not sure it can be done purely with CSS, unless you're comfortable in sort of faking it with illusions. Maybe use Josh Mein's answer, and set #container to overflow:hidden.
For what it's worth, here's a jQuery solution:
var contH = $('#container').height(),
upH = $('#up').height();
$('#down').css('height' , contH - upH);