Set flex item height to size of content - html

I have three divs in a column. Each div has content that should scroll if it overflows. I would like each div to have the same height, with the max height of each div to be the height of its content. Is this possible to implement using flexbox?
Jsfiddle: http://jsfiddle.net/x6puccbh/2/
As you can see in the fiddle, all three sections are the same height, but I would like the middle section to be only as tall as its content.
<div class="container">
<div class="panel">
<div class="section">
<div class="header">HEADER</div>
<div class="content">content<br>content<br>content<br>content
<br>content<br>content<br>content<br>content
<br>content<br>content<br>content<br>content</div>
</div>
<div class="section">
<div class="header">HEADER</div>
<div class="content">content</div>
</div>
<div class="section">
<div class="header">HEADER</div>
<div class="content">content<br>content<br>content<br>content
<br>content<br>content<br>content<br>content
<br>content<br>content<br>content<br>content
</div>
</div>
</div>
.container {
height: 300px;
}
.panel {
display:flex;
flex-direction: column;
height: 100%;
}
.header {
height: 15px;
text-align: center;
flex-shrink: 0;
}
.section {
flex-grow: 1;
flex-shrink: 1;
flex-basis: auto;
height: 100%;
border: 1px solid red;
display: flex;
flex-direction: column;
}
.content {
overflow-y: auto;
height: 100%;
}

does this work for you?
<div class="section">
<div class="header">HEADER</div>
<p>content sjkdkjasdn asjn dvas jkdb ajd avsd</p>
</div>
css
.section:nth-child(2) {
height:unset;
}
p {
padding-bottom: 5em;
}
here's a fork of the fiddle

Use this:
height: fit-content;
Can you use link:
https://caniuse.com/?search=fit-content

Related

Create a circle that fills up the remaining space in a flexbox cell

I have a 2-cell flexbox with a fixed-height (mobile screen), and one cell stacked on top of the other. I need all of the content of the top-cell to be displayed.. the bottom-cell should yield as much space as possible to allow this. This part was easy.
.main-container {
height: 400px;
width: 200px;
display: flex;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background-color: lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
... with that the content-container will grow as needed (in this example it's 100px) and the rest is taken up by the remaining-space cell.
What I need to do is fill the remaining-space cell with a circle that is as big as it can be, but doesn't force the remaining-space cell to grow in height/width... and I need to do it with just html/css.
The only way I've seen to enforce a 1:1 ratio (square/circle) is by using the padding-bottom trick where the padding is calculated using the element's width. This doesn't work for me because remaining-space cell might have a larger width than it's height.. which will cause the cell to grow in height. This is especially difficult in that the container is responsive so the actual width in pixels is never known.
A simple gradient can do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background:
radial-gradient(circle closest-side, red 98%, transparent)
lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
Clip-path can also do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side)
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
Where you can also have content inside
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side);
display:flex;
align-items:center;
justify-content:center;
font-size:30px;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>

Why doesn't flex direction column with align-items=center center image properly

I stumbled upon an issue with image centering within a flexbox with direction:column.
Imagine you have two elements within a flexbox, where the first one contains an image:
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
.image-container {
flex: 1;
align-self: center;
.img {
height: 100%;
}
}
.another-flex-child {
flex: none;
background-color: red;
}
}
I would expect the image to be center horizontally within the div, but it appears the left border of the image is exactly at the center of the div.
When I replace the image with another div which contains some text it is placed as expected.
Can anybody explain to me whats happening there?
Checkout this fiddle
Because your <div> that contains the image (and has align-self: center on it) is by default a block-level element, and has a width of 100% by default. As such, it is constrained in relation to the parent.
In order to have your image centered correctly, you'll want to add display: contents with:
container .image-container {
display: inline;
}
This can be seen in the following:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.container .image-container {
flex: 1;
align-self: center;
display: contents;
}
.container .image-container .img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
The issue is that you are using an SVG with no intrinsic dimension and only an intrinsic ratio so it's like your image has a width equal to 0 which make its centred container with a width equal to 0, too.
Here is before using height:100%
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
}
.img {
/*height: 100%;*/
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
After setting height:100% the image will fill all the space and will keep its ratio but you will have an overflow because the browser will not go back to calculate the width of the container again:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
To avoid this give the image a width and make sure to add min-height:0 to the container to allow it to shrink
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" width="250">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
If you were initially using an image with intrinsic dimension you won't have this issue and you don't need to define a width. You will only need to add min-height:0 to avoid the overflow:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/400/400">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Note that the above doesn't work the same way in Firefox and you will need to add text-aling:center to make sure it works the same everywhere:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
text-align:center;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/400/400">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
You will notice that the difference is related to the width calculation of the container which a bit complex due to the use of height:100%
Things may get worse if the size of the image is very small:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
text-align:center;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/50/50">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
In Firefox text-align:center will do nothing and you may need a nested flexbox container
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
justify-content:center;
border:2px solid blue;
display:flex;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/50/50">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
The below is almost the same issue you were having with the initial SVG that can fixed with this same code but it won't remove the overflow:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
display:flex;
justify-content:center;
border:2px solid blue;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Another intresting thing to note is that your initial code may work fine if you add height:100% to the container making the calculation of the nested height easier:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
box-sizing:border-box;
height:100%;
}
.img {
height: 100%;
display:block;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Add the justify-content like below:
.image-container {
flex: 1;
align-self: center;
justify-content:center;
}
it should works

Arranging flex-items in a particular way

I'd like to arrange flex-items in the following manner:
Using the following example:
.Container {
display: flex;
overflow: hidden;
height: 100vh;
margin-top: -100px;
padding-top: 100px;
position: relative;
width: 70vw;
}
<div class="Top">Top Content</div>
<div class="Container">
<div class="Left">Left Content</div>
<div class="Middle">Middle Content</div>
<div class="Right">Right Content</div>
</div>
I can make it so there is a horizontal bar and vertical columns under it. However, I cannot figure out how to make another vertical column; one consisting of the above code, and the other a different div.
Thanks!
You can use flex. For each "direction" use a container. To divide ratio 1:2 use flex-grow: 1 and flex-grow: 2;.
It's also important to use
flex-shrink: 0;
flex-basis: 0;
if you want to keep the ratio regardless of the content inside, otherwise, the browser will resize the divs according to the content inside them.
There is a shorter way of writing all the 3:
flex: [flex-grow], [flex-shrink], [flex-basis];
but IE doesn't support it, so I prefer using the long way
.out-container {
display: flex;
flex-direction: row;
}
.inner-cont {
display: flex;
flex-direction: row;
flex-grow: 2;
}
.container {
flex-grow: 2;
flex-shrink: 0;
flex-basis: 0;
}
.container {
display: flex;
flex-direction: column;
height: 100vh;
width: 70vw;
}
.left,
.right,
.middle,
.top {
padding: 10px;
border: 1px solid black;
}
.left {
flex-grow: 1;
flex-shrink: 0;
flex-basis: 0;
background-color: #aaeffe;
}
.top {
flex-basis: 0;
flex-grow: 1;
flex-shrink: 0;
background-color: #69e2fd;
}
.middle{
flex-basis: 0;
flex-grow: 1;
flex-shrink: 0;
background-color: #38d0fd;
}
.right{
flex-basis: 0;
flex-grow: 1;
flex-shrink: 0;
background-color: #1fbbfb;
}
<div class="out-container">
<div class="left">Left Content</div>
<div class="container">
<div class="top">Top content</div>
<div class="inner-cont">
<div class="middle">Middle Content</div>
<div class="right">Right Content</div>
</div>
</div>
</div>
<html>
<head>
<title>Page Title</title>
<style>
body{display:table}
.row{display:table-row}
.cell{display:table-cell}
.floatLeft{float:left}
.box1{background-color:#f00;width:100px;height:400px}
.box2{background-color:#0f0;width:400px;height:100px}
.box3{background-color:#00f;width:200px;height:300px}
.box4{background-color:#f0f;width:200px;height:300px}
</style>
</head>
<body>
<div class="row">
<div class="cell box1"></div>
<div class="cell">
<div class="row">
<div class="cell box2 "></div>
</div>
<div class="row">
<div class="cell box3 floatLeft"></div>
<div class="cell box4 floatLeft"></div>
</div>
</div>
</div>
</body>
</html>

Can flexbox fill the entire screen without access to the 'body'?

In my situation I'm not able to apply flex to the body tag. Can I achieve the same effect (sticky header/footer with the flexbox taking up the full screen) without applying css to the body tag. Here is the relevant code. I commented out the body css that achieves the effect I want.
Thanks,
Matt
/*html {
height: 100%;
}
body {
min-height: 100%;
display: flex;
flex-direction: column;
}
*/
.flex-body {
min-height: 100%;
display: flex;
flex-direction:column;
}
.main {
display: flex;
flex: 1 0 auto;
}
.nav {
flex: 0 0 12em;
}
.content {
flex: 1 0 auto;
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex: 1 0 auto;
flex-direction: row;
}
.col {
flex: 1 0 auto;
}
/* TEMP CODE FOR THIS TEST, REMOVE FOR ACTUAL USE
*/
body {
text-align: center;
}
*{
box-shadow:inset 0px 0px 0px 1px #f00;
}
<div class="flex-body">
<header class="header">
<section class="content">
<div class="row">
<div class="col">
Upper Left
</div>
<div class="col">
Upper Middle
</div>
<div class="col">
Upper Right
</div>
</div>
</section>
</header>
<main class="main">
<nav class="nav">
Nav
</nav>
<section class="content">
<div class="row">
<div class="col">
Upper Left
</div>
<div class="col">
Upper Middle
</div>
<div class="col">
Upper Right
</div>
</div>
<div class="row">
Middle
</div>
<div class="row">
Lower
</div>
</section>
</main>
<footer class="footer">Footer</footer>
</div>
you can also imbricate flex boxe and use flex shorthands to fill entire parent's height or width . But this means to include html & body .
This way you do need to deal with height/width and margins/paddings. The browser will deal with it itself.
html {
height: 100%;
display: flex;
flex-direction: column;
}
body,
.flex-body {
display: flex;
flex: 1;/* no need anymore to deal with height/width */
flex-direction: column;
}
.main {
display: flex;
flex: 1;
/* mind this */
/*overflow:auto; */ /* can come handy here if you want to keep footer in view */
}
.nav {
flex: 0 0 12em;
}
.content {
flex: 1 0 auto;
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex: 1 0 auto;
flex-direction: row;
}
.col {
flex: 1 0 auto;
}
/* TEMP CODE FOR THIS TEST, REMOVE FOR ACTUAL USE
*/
body {
text-align: center;
}
* {
box-shadow: inset 0px 0px 0px 1px #f00;
}
<div class="flex-body">
<header class="header">
<section class="content">
<div class="row">
<div class="col">
Upper Left
</div>
<div class="col">
Upper Middle
</div>
<div class="col">
Upper Right
</div>
</div>
</section>
</header>
<main class="main">
<nav class="nav">
Nav
</nav>
<section class="content">
<div class="row">
<div class="col">
Upper Left
</div>
<div class="col">
Upper Middle
</div>
<div class="col">
Upper Right
</div>
</div>
<div class="row">
Middle
</div>
<div class="row">
Lower
</div>
</section>
</main>
<footer class="footer">Footer</footer>
</div>
Add a min-height of 100vh to the flex container:
.flex-body {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
}
Then it will be at least as tall as the browser’s viewport (but will be allowed to grow taller if necessary).

Flex - make parent width of children?

I have a flex box layout. I want the width of .outer-2 to be the width of its children, with .outer-1 and outer-3 taking up the rest of the space.
How can I achieve this?
JSFiddle
.container {
display: flex;
}
.outer-1 {
background: red;
height: 100px;
flex: 1;
}
.outer-2 {
display: flex;
flex: 1;
}
.outer-3 {
background: blue;
height: 100px;
flex: 1;
}
.inner {
flex-basis: 30px;
background: green;
height: 100px;
margin: 0 3px;
}
<div class="container">
<div class="outer-1">
</div>
<div class="outer-2">
<div class="inner">
</div>
<div class="inner">
</div>
<div class="inner">
</div>
</div>
<div class="outer-3">
</div>
</div>
You need to change the flex properties for the second child of container preventing it from growing to fit it's parent. That, and adding a width or min-width to each .inner element will prevent their parent from collapsing them down.
.container{
display: flex;
}
.outer-1{
background: red;
height: 100px;
flex: 1;
}
.outer-2{
display: flex;
flex: 1;
}
.outer-3{
background: blue;
height: 100px;
flex: 1;
}
.inner{
width: 30px;
flex: 1 0 30px;
background: green;
height: 100px;
margin: 0 3px;
}
<div class="container">
<div class="outer-1">
</div>
<div class="outer-2">
<div class="inner">
</div>
<div class="inner">
</div>
<div class="inner">
</div>
</div>
<div class="outer-3">
</div>
</div>