Failed to use flexbox to stretch to full page height - css

I'm trying to use flexbox for a full page lay-out, but when there isn't enough text in the main area, it isn't stretched vertically to fill the remaining space of the page as I expected.
It behaves like I specified align-content: space-between, but I didn't. What am I doing wrong here?
body {
display: flex;
flex-flow: row wrap;
align-content: stretch;
/* no effect here */
height: 100%;
width: 100%;
margin: 0px;
}
body > #header-area {
flex: 1 1 auto;
order: 1;
width: 100%;
height: 150px;
}
body > #menu-area {
flex: 0 0 180px;
order: 2;
}
body > #main-area {
flex: 1 1 auto;
order: 3;
}
body > #aside-area {
flex: 0 0 150px;
order: 4;
}
body > #footer-area {
flex: 1 1 auto;
order: 5;
width: 100%;
height: 100px;
}
<div id="main-area" style="background-color: aqua">
main area
</div>
<div id="menu-area" style="background-color: lavender">
menu area
</div>
<div id="aside-area" style="background-color: lemonchiffon">
sidebar area
</div>
<div id="header-area" style="background-color: lightsteelblue">
header area
</div>
<div id="footer-area" style="background-color: lightskyblue">
footer area
</div>
Thanks for any help!

If you can wrap your middle content, then I would do it like this
html {height:100%;} /* add this */
body {
display: flex;
flex-direction: column;
min-height: 100%; /* change this to min-height */
width: 100%;
margin: 0;
padding:0;
}
body > #header-area {
/* flex: 1 1 auto; - not sure what this is for so I have removed it */
order: 1;
width: 100%;
height: 150px;
}
#menu-area {
flex: 0 0 180px;
order:1;
}
#main-area {
flex: 1 1 auto;
order:2;
}
#aside-area {
flex: 0 0 150px;
order:3;
}
body > #footer-area {
/* flex: 1 1 auto; - not sure what this is for so I have removed it */
order: 3;
width: 100%;
height: 100px;
}
#content {
flex-direction:row;
display:flex;
flex-grow:1;
order:2;
}
<div id="content">
<div id="main-area" style="background-color: aqua">
main area
</div>
<div id="menu-area" style="background-color: lavender">
menu area
</div>
<div id="aside-area" style="background-color: lemonchiffon">
sidebar area
</div>
</div>
<div id="header-area" style="background-color: lightsteelblue">
header area
</div>
<div id="footer-area" style="background-color: lightskyblue">
footer area
</div>

Related

How to apply scorlbar to a section inside a flexbox?

Consider the following:
* {padding: 0; margin: 0; }
body {
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
}
header {
flex: 0 0 50px;
background-color: lightgray;
}
div#wrapper {
flex: 1 0 0px;
display: flex;
flex-direction: row;
}
aside {
background-color: darkgray;
flex: 0 0 50px;
}
main {
display: block;
flex: 1 1 0px;
background-color: aliceblue;
}
div#content {
width: 60px;
height: 2000px;
margin: 10px;
background-color: red;
}
div#content-wrap {
width: 100%;
height: 100%;
}
div#content-container {
height: 100%;
overflow-y: scroll;
}
<html>
<head></head>
<body>
<header></header>
<div id="wrapper">
<aside></aside>
<main>
<div id="content-wrap">
<div id="content-container">
<div id="content"></div>
</div>
</div>
</main>
</div>
</body>
</html>
In the snippet above, the <body> fills all the available space, it's consisted of a <header> which takes an arbitrary height and a <div id="wrapper"> that takes the rest of available height. The aforementioned "#wrapper" has a "sidebar" that has an arbitrary width and a "<main>" section to take the rest of the width. I want only the "main" section to be scrollable, but applying a long enough "#content" causes the "body" to get the scrollbar, instead! (while I've enforced the heights to be 100%) So, how to fix this?
here only remove same height according to <header></header> from <div id="wrapper"> bcz of normaly it will take 100% height #wrapper so only add height: calc(100% - 50px);
div#wrapper {
flex: 1 0 0px;
display: flex;
flex-direction: row;
height: calc(100% - 50px);
}
and it will be working like below ss

flexbox makes content disappear

I'm playing around with flexbox to get the hang of it but I am running into some issues. My goal is to have the window separated by four background colors where the first is just a header row and then the rest of the page is filled by 3 columns each a different background color. But for some reason if I write display: flex it doesn't show anything. Can someone explain to me how to get this desired effect?
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
}
.col {
flex: 1;
}
.col-container:nth-child(1) {
background: green;
}
.col-container:nth-child(2) {
background: blue;
}
.col-container:nth-child(3) {
background: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
</div>
</div>
</body>
Here is a working example:
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
}
.col-1 {
flex: 1 1 33.333%;
background-color: green;
}
.col-2 {
flex: 1 1 33.333%;
background-color: blue;
}
.col-3 {
flex: 1 1 33.333%;
background-color: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col-1">ts</div>
<div class="col-2">dtd</div>
<div class="col-3">dt</div>
</div>
</div>
</body>
Here's what you needed to fix:
Set flex-direction to row. You most likely want the columns next to each other.
Add the classes to your HTML for the col-1, col-2 and col-3.
You need content in those col classes, or you won't see anything anyway.
I set a flex-basis (the third parameter in the flex shorthand) to 33.333%. You don't necessarily need this, but it's nice to see how much space a particular element will fill or change it.
EDIT For the comments:
body {
margin: 0;
padding: 0;
}
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
height: calc(100vh - 150px);
}
.col-1 {
flex: 1 1 33.333%;
background-color: green;
}
.col-2 {
flex: 1 1 33.3333%;
background-color: blue;
}
.col-3 {
flex: 1 1 33.3333%;
background-color: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col-1"></div>
<div class="col-2"></div>
<div class="col-3"></div>
</div>
</div>
</body>
Basically, you need to give the col-container a height. To achieve this, I used vh units in the calc statement. It subtracts your header height from the viewport height and gives the remainder. This also removes the necessity for filler content.

logical difference between flex: none and flex: 0 0 100% for mobile

the visual view of the tile is the same as for all tile, but I would like to know which will be logically correct to set 100% of tile width using flexbox property. where the flex: none or flex: 0 0 100%, because as per the bootstrap4 grid system they used flex: 0 0 100%;
img {
border: 0;
vertical-align: middle;
height: 180px;
overflow: hidden;
position: relative;
display: block;
width: 100%;
}
.flex {
display: flex;
}
.flex div {
border: 1px solid;
max-width: 299px;
}
.auto {
flex: 0 0 auto;
}
.hund {
flex: 0 0 100%;
}
.none {
flex: none;
}
#media (min-width: 768px) {
.flex div {
flex: 0 0 33.3333333%;
max-width: 33.3333333%;
}
}
<div class="flex">
<div class="auto">
<img src="https://via.placeholder.com/340x230"> This is flex-basis auto
</div>
</div>
<div class="flex">
<div class="hund">
<img src="https://via.placeholder.com/340x230"> This is flex-basis hund
</div>
</div>
<div class="flex">
<div class="none">
<img src="https://via.placeholder.com/340x230"> This is flex-basis none
</div>
</div>
<div class="flex">
<div class="pointless"><img src="https://via.placeholder.com/340x230"> This is flex-basis pointless
</div>
</div>

Why isn't `height: 100%` and absolute positioning working in flexbox?

I'm trying to make a child div of a flexbox layout fill its parent. In any other context setting the width/height to 100% causes a div to fill its parent... I only wish to use flexbox for my top level layout.
Problems
#map-container div will not fill #col1 even though it has height 100% set.
#controls div appears outside #col1 completely. I've previously used absolute layout to align boxes to corners without problems. Being inside a flexbox grand-parent seems to cause issues.
What I'm expecting is #map-container and #map to fill #col1 and #controls to align to bottom right-hand corner of #map.
.wrapper, html, body {
height:100%;
margin:0;
}
#col1 {
display: flex;
}
#map-container {
background-color: yellow;
width: 100%;
height: 100%;
}
#map {
background-color: purple;
width: 100%;
height: 100%;
}
#controls {
background-color: orange;
position: absolute;
right: 3px;
bottom: 3px;
width: 100px;
height: 20px;
}
.wrapper {
display: flex;
flex-direction: column;
}
#row1 {
background-color: red;
}
#row2 {
flex:2;
display: flex;
}
#col1 {
background-color: green;
flex: 1 1;
}
#col2 {
background-color: blue;
flex :0 0 240px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<div id="map-container">
<div id="map">
Map
</div>
<div id="controls">Controls</div>
</div>
</div>
<div id="col2">Sidebar</div>
</div>
</div>
#map-container div will not fill #col1 even though it has height 100% set.
It won't work that way, because for a percentage unit to work, it needs to have height set on its parent all the way up. This fights against the flex model, where the flex-items are distributed and arranged by the flex-box layout and have no dimensions set. Why use a flex layout when all your elements are 100%? Either do a 100% on all your element all the way up, or do a flex on all containers.
If you stick to flex layout, then you will have to get into nested flex. Otherwise, you will get #map-container to fill-up, but not the #map.
This fiddle http://jsfiddle.net/abhitalks/sztcb0me illustrates that problem.
#controls div appears outside #col1 completely. I've previously used absolute layout to align boxes to corners without problems. Being
inside a flex-box grand-parent seems to cause issues.
The only issue is that you are positioning it absolutely, but in relation to what? You need to position your #map-container relatively for that to work.
Here is how:
Fiddle: http://jsfiddle.net/abhitalks/sztcb0me/1/
Snippet:
* { box-sizing: border-box; padding: 0; margin: 0; }
html, body, .wrapper { height:100%; width: 100%; }
.wrapper { display: flex; flex-direction: column; }
#row1 { flex: 0 1 auto; background-color: red; }
#row2 { flex: 2 0 auto; display: flex; }
#col1 { flex: 1 0 auto; display: flex; background-color: green; }
#col2 { flex: 0 0 240px; background-color: blue; }
#map-container {
flex: 1 0 auto; display: flex;
position: relative; background-color: yellow;
}
#map { flex: 1 0 auto; background-color: purple; }
#controls {
background-color: orange;
position: absolute;
right: 3px; bottom: 3px;
width: 100px; height: 20px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<div id="map-container">
<div id="map">
Map
</div>
<div id="controls">Controls</div>
</div>
</div>
<div id="col2">Sidebar</div>
</div>
</div>
the problem is that it's wrapped in #map-container
.wrapper, html, body {
height:100%;
margin:0;
}
#col1 {
display: flex;
}
#map-container {
background-color: yellow;
width: 100%;
height: 100%;
}
#map {
background-color: purple;
width: 100%;
/* height: 100%; */
display: flex;
flex-wrap: wrap-reverse;
justify-content: space-between;
}
#controls {
background-color: orange;
position: relative;
/*right: 3px;
bottom: 3px;*/
width: 100px;
height: 20px;
}
.wrapper {
display: flex;
flex-direction: column;
}
#row1 {
background-color: red;
}
#row2 {
flex:2;
display: flex;
}
#col1 {
background-color: green;
flex: 1 1;
}
#col2 {
background-color: blue;
flex :0 0 240px;
}
<div class="wrapper">
<div id="row1">Header</div>
<div id="row2">
<div id="col1">
<!-- <div id="map-container"> -->
<div id="map">
Map
<div id="controls">Controls</div> <!-- add it here -->
</div>
<!-- <div id="controls">Controls</div> -->
<!--</div> -->
</div>
<div id="col2">Sidebar</div>
</div>
</div>
adding an absolute position controls in that way is not optimal (in the snippet I commented it out) ; you can place the controlsnested in #map (and use flex properties for correcting placement)

position sticky automatic "top" position

Is there a way for stickies to take into account other stickes on the page?
For example:
body {
display: flex;
min-height: 2000px;
flex-direction: column;
}
#header {
height: 40px;
flex: 0 0 auto;
position: sticky;
top: 0;
background: yellow;
}
#footer {
flex: 0 0 auto;
height: 20px;
}
#main {
display: flex;
flex: auto;
background: blue;
}
#side {
width: 200px;
background: red;
}
#side > div {
position: sticky;
top: 0px;
}
<div id="header">header</div>
<div id="main">
<div id="side">
<div>side</div>
</div>
<div id="content">
content
</div>
</div>
<div id="footer">footer</div>
Notice that if I scroll down the header will overlap the sidebar because they have the same top position.
To fix I have to make the top position of the sidebar take the value of the header height
body {
display: flex;
min-height: 2000px;
flex-direction: column;
}
#header {
height: 40px;
flex: 0 0 auto;
position: sticky;
top: 0;
background: yellow;
}
#footer {
flex: 0 0 auto;
height: 20px;
}
#main {
display: flex;
flex: auto;
background: blue;
}
#side {
width: 200px;
background: red;
}
#side > div {
position: sticky;
top: 40px;
}
<div id="header">header</div>
<div id="main">
<div id="side">
<div>side</div>
</div>
<div id="content">
content
</div>
</div>
<div id="footer">footer</div>
But what if the header has variable height? Can I tell the browser somehow to position the stickies so they dont overlap others?
I think you would need to use javascript for this. First to get the height of the header and then set the top position of your side div using that value. I am not aware of any pure css way of doing it I am afraid.
If you are using jQuery it is simply using the .height() method if not you can use this:
var clientHeight = document.getElementById('myDiv').clientHeight;
var offsetHeight = document.getElementById('myDiv').offsetHeight;
The offset method gets the height with any padding and borders.

Resources