Div with 100% height with Display: Grid - html

I have a container div that has a header, a content area and a footer. And I want the footer to always be stuck to the bottom, while the content area always fills the remaining space. And I don't know how to do that.
This is what I have currently:
.container {
display: grid;
/*position: relative;*/
grid-template-columns: 1fr;
border: 1px solid black;
}
.header {
background-color: yellow;
display: grid;
grid-template-columns: 3fr 3fr 3fr 1fr;
padding: 10px 0;
}
.content {
background-color: teal;
position: relative;
display: grid;
grid-template-columns: 1fr 7fr 1fr;
padding: 15px 20px 20px 0;
min-height: 100%;
}
.footer {
background-color: maroon;
position: absolute;
width: 100%;
bottom: 0;
}
<div class="container">
<div class="header">This is a header.</div>
<div class="content">This is a content area.</div>
<div class="footer">This is a footer.</div>
</div>
As you can see, the content section doesn't stretch all the way to the footer section. What am I missing here?
Thanks!

Use grid-template-rows: auto 1fr auto; - this way footer and header will take only space that they need, and content will take everything else. Also, remove position: absolute; from footer to make it a grid-item.
body {
margin: 0;
}
* {
box-sizing: border-box;
}
.container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
border: 1px solid black;
min-height: 100vh;
}
.header {
background-color: yellow;
padding: 10px 0;
}
.content {
background-color: teal;
padding: 15px 20px 20px 0;
min-height: 100%;
}
.footer {
background-color: maroon;
width: 100%;
}
<div class="container">
<div class="header">This is a header.</div>
<div class="content">This is a content area.</div>
<div class="footer">This is a footer.</div>
</div>

<script>
$(document).ready(function(e) {
var h = $( window ).height();
$('.container').css('max-height', h-220+'px');
});
</script>
This is for container height if your footer height is 220px. You can change the height as per your need.
<style>
.footer{ bottom:0; position:fixed; }
</style>
This is for footer to fixed at bottom.

Related

Header Sticky Position in CSS Grid Layout

I'm learning CSS Grid layout and i have a problem about positioning.
What i want is to create a page layout composed by a left-side menu, top-bar menu and a main content page like the image below:
I have been able to achieve the goal, but now i want to fix the position of the top bar and sidebar while main content is scrolling.
I set position:sticky to both containers but it does not working.
How can i fix?
Here is my code:
* {
margin: 0 !important;
padding: 0 !important;
box-sizing: border-box !important;
}
.grid-container {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: 10% 100vh;
grid-template-areas:
"LeftMenu TopMenu"
"LeftMenu Main";
}
.LeftMenu {
background-color: #a4a4a4;
grid-area: LeftMenu;
width: 200px;
height: 100%;
}
.TopMenu {
background-color: #d49494;
grid-area: TopMenu;
width: 100%;
height: 100%;
display: flex;
}
.Main {
background-color: #8990eb;
grid-area: Main;
width: 100%;
height: 100vh;
}
<div class="xdg-component-appnav-menu">
<div class="grid-container">
<div class="LeftMenu">left menu</div>
<div class="TopMenu">top menu</div>
<div class="Main">
<p style="padding-bottom: 1000px;">Content</p>
</div>
</div>
</div>
You don't need position: sticky. It's extra complication and still isn't fully supported by some browsers.
Just use overflow: auto on the main container.
.grid-container {
display: grid;
height: 100vh;
grid-template-columns: 200px 1fr;
grid-template-rows: 10% 90%;
grid-template-areas:
"LeftMenu TopMenu"
" LeftMenu Main ";
}
.LeftMenu {
grid-area: LeftMenu;
background-color: #a4a4a4;
}
.TopMenu {
grid-area: TopMenu;
background-color: #d49494;
}
.Main {
grid-area: Main;
overflow: auto; /* key adjustment */
background-color: #8990eb;
}
body {
margin: 0;
}
<div class="xdg-component-appnav-menu">
<div class="grid-container">
<div class="LeftMenu">left menu</div>
<div class="TopMenu">top menu</div>
<div class="Main">
<p style="height: 1000px;">Content</p>
</div>
</div>
</div>

Toggling rows in and out in CSS Grid Layout

I have the following layout with 2 headers and 3 footers:
.my-grid {
display: grid;
grid-template-areas:
"header1"
"header2"
"mainAreaExpandMePlease"
"footer1"
"footer2"
"footer3"
;
grid-template-rows: 27px 27px 1fr 28px 28px 28px;
height: 100%;
}
The main area will expand to fill the gap left after showing the headers and footers.
I want to be able to toggle footers on and off (show / hide them) such that they collapse. With the code above, a gap will be left in place of the footer when we hide it.
How should I go about:
Having a main area that always expands
Having optional headers and footers which collapse, when hidden
Examples:
If header1 collapses, then header2 should take its place and mainAreaExpandMePlease should expand to where header2 used to be
If header2 collapses, then mainAreaExpandMePlease should expand up by another 27px
If footer3 collapses, then footer2 takes place of footer3, footer1 takes the place of footer2 and mainAreaExpandMePlease will stretch down another 28px
Thank you!
Fiddle: https://jsfiddle.net/jg6ho4wu/1/
html, body {
height: 100%;
margin: 0;
padding: 0;
}
.my-grid {
display: grid;
grid-template-areas:
"header1"
"header2"
"mainAreaExpandMePlease"
"footer1"
"footer2"
"footer3";
grid-template-rows: 27px 27px 1fr 28px 28px 28px;
height: 100%;
}
.header1 {
grid-area: header1;
background-color: yellow;
}
.header2 {
grid-area: header2;
background-color: magenta;
}
.mainAreaExpandMePlease {
grid-area: mainAreaExpandMePlease;
background-color: cyan;
}
.footer1 {
grid-area: footer1;
background-color: green;
}
.footer2 {
grid-area: footer2;
background-color: red;
}
.footer3 {
grid-area: footer3;
background-color: blue;
}
<div class="my-grid">
<div class="header1"></div>
<div class="header2"></div>
<div class="mainAreaExpandMePlease"></div>
<div class="footer1"></div>
<div class="footer2" style="display:none"></div>
<div class="footer3"></div>
</div>
Don't set the height of the header and footer rows at the container level.
Set their heights on the items, and set their container heights to auto.
.my-grid {
display: grid;
height: 100vh;
grid-template-rows: auto auto 1fr auto auto auto;
grid-template-areas: "header1"
"header2"
"mainAreaExpandMePlease"
"footer1"
"footer2"
"footer3";
}
.header1 {
height: 27px;
grid-area: header1;
background-color: yellow;
}
.header2 {
height: 27px;
grid-area: header2;
background-color: magenta;
}
.mainAreaExpandMePlease {
grid-area: mainAreaExpandMePlease;
background-color: cyan;
}
.footer1 {
height: 28px;
grid-area: footer1;
background-color: green;
}
.footer2 {
height: 28px;
grid-area: footer2;
background-color: red;
}
.footer3 {
height: 28px;
grid-area: footer3;
background-color: blue;
}
body {
margin: 0;
padding: 0;
}
<div class="my-grid">
<div class="header1"></div>
<div class="header2"></div>
<div class="mainAreaExpandMePlease"></div>
<div class="footer1"></div>
<div class="footer2" style="display:none"></div>
<div class="footer3"></div>
</div>

A cleaner way to create a header/content CSS Grid layout

I'm trying to create a fairly simple site layout but being new to CSS Grid, I'm pretty sure I'm going about it the wrong way.
body{
margin: 0;
padding: 0;
}
.container {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
grid-template-rows: 120px 450px;
}
.header,
.main {
border: 1px solid black;
}
.side {
background-color: antiquewhite;
border-bottom: 1px solid black;
}
<div class="container">
<div class="side">Should have the same background color/gradient as header</div>
<header class="header">Header</header>
<div class="side">Should have the same background color/gradient as header</div>
<div class="side">Should have the same background color/gradient as Content</div>
<main class="main">Content</main>
<div class="side">Should have the same background color/gradient as Content</div>
</div>
This is sort of what I'm going for: a header and a main section, with the content of both kept to the center of the page - but at the same time I want the whole of both rows to have their own background colors. But my solution uses a bunch of unneeded divs and the use of grid-template-rows: 150px 450px; is wrong too since I want the content to take up the rest of the page not 450px.
How can I achieve this?
Try giving max-width and margin to the container class
.container{
max-width:calc( (3/5) * 100vw);
margin:0 auto;
grid-template-rows: 120px 1fr;
display:grid;
}
You can simplify like this:
body {
margin: 0;
padding: 0;
display: grid;
grid-template-columns: 1fr 3fr 1fr;
min-height:100vh;
background:
linear-gradient(red, blue) top/100% 120px no-repeat,
linear-gradient(green, grey) bottom/100% calc(100% - 120px) no-repeat;
}
body:before,
body:after{
content:"";
}
.container {
display: grid;
grid-template-rows: 120px 1fr;
}
.header,
.main {
border: 1px solid black;
}
<div class="container">
<header class="header">Header</header>
<main class="main">Content</main>
</div>
And if it's the only content you will have inside body you can also use max-width and vw unit like this:
body {
margin: 0;
padding: 0;
background:
linear-gradient(red, blue) top/100% 120px no-repeat, /*Cover the header*/
linear-gradient(green, grey) bottom/100% calc(100% - 120px) no-repeat; /*Cover the content*/
}
.container {
/* you want 1f 3fr 1fr so we have 5fr so we need (3/5)*/
max-width:calc( (3/5) * 100vw);
margin:auto;
display: grid;
grid-template-rows: 120px 1fr;
min-height:100vh;
}
.header,
.main {
border: 1px solid black;
}
<div class="container">
<header class="header">Header</header>
<main class="main">Content</main>
</div>
Try this one:
body {
margin: 0;
padding: 0;
}
div.container {
display: grid;
grid-template-columns: 1fr 3fr 1fr;
grid-template-rows: 150px; 1fr;
height: 100vh;
}
.header-container, .content-container {
display: contents;
}
.header-container div {
background: #ddd;
}
.content-container div {
background: #aaa;
}
<body>
<div class="container">
<div class='header-container'>
<div class='side'>Side</div>
<div class='header'>Header</div>
<div class='side'>Side</div>
</div>
<div class='content-container'>
<div class='side'>Side</div>
<div class='content'>Content</div>
<div class='side'>Side</div>
</div>
</div>
</body>

Zooming in makes div hover over fixed-position img

I have a header which has an img for the logo (position: fixed) and a grid which is centered using margins, which contains whatever except for the logo is in the header. The HTML looks something like this:
<div id='header'>
<img id='logo' src='http://i65.tinypic.com/dw2nw9.png'>
<div id='header-grid'>
<div id='item-one'></div>
<div id='item-two'></div>
<div id='item-three'></div>
<div id='item-four'></div>
</div>
</div>
And the CSS looks like this:
#header {
position: fixed;
width: 100%;
height: var(--header-height);
background-color: var(--main-color);
z-index: 3141592;
}
#logo {
position: fixed;
max-width: 100px;
max-height: var(--header-height);
padding-left: 10px;
}
#header-grid {
width: 900px;
margin: 0 auto;
height: var(--header-height);
display: grid;
grid-template-columns: auto auto auto auto;
}
Now, when I zoom in, the #header-grid goes over the #logo. I want them to stay next to each other instead of one going on top of the other
Found a grid solution for you:
#header {
position: fixed;
width: 100%;
height: var(--header-height);
background-color: var(--main-color);
z-index: 3141592;
display: grid;
/* add the following */
grid-template-columns: 1fr repeat(2, auto) 1fr; /* not sure about grid but you need the repeat so the second column can be centred */
justify-items: center;
}
#logo {
max-width: 100px;
max-height: var(--header-height);
margin-left: 10px; /* change this to margin as you shouldn't add padding to images */
margin-right: auto; /* add this to push to the left */
}
#header-grid {
margin: 0 auto;
height: var(--header-height);
display: grid;
grid-template-columns: auto auto auto auto;
grid-column-start: 2; /* add this so it sits in centre */
/* for demo */
width: 300px;
border: 1px solid red;
}
<div id='header'>
<img id='logo' src='http://i65.tinypic.com/dw2nw9.png'>
<div id='header-grid'>
<div id='item-one'></div>
<div id='item-two'></div>
<div id='item-three'></div>
<div id='item-four'></div>
</div>
</div>

Allow one grid item to scroll with fixed header and sidebar

I have a grid layout with two columns and two rows. A sticky left nav, a sticky header, and content that will live in the bottom right corner of the grid.
What I have now is nearly there, but I would like the .content div to use scroll when content extends beyond the screen. I thought I would be able to just use overflow: auto, but that isn't working. Is what I have close?
body {
margin: 0;
overflow: hidden;
}
.page {
display: grid;
grid-template-rows: 55px auto;
grid-template-columns: 20vh auto;
grid-template-areas: "nav header" "nav content";
}
.nav {
grid-area: nav;
background-color: blue;
}
.header {
grid-area: header;
background-color: grey;
}
.content {
grid-area: content;
height: 1000px; // This is dynamic
background-color: red;
}
<div class="page">
<div class="nav">Side nav</div>
<div class="header">Header</div>
<div class="content">
<h1>title</h1>
</div>
<div>
JS fiddle
For overflow: auto to work (i.e., for scrollbars to render) browsers need a trigger. This trigger is usually a height / width limitation that forces an overflow condition, which launches the scrollbars.
Trigger conditions vary among browsers. They also vary among CSS technologies, such as flex, grid and block layouts.
In this particular case, there are several logical places to establish an overflow condition, but none of them work.
You could target the grid item, as you have tried:
.content {
height: 1000px
overflow: auto;
}
But it doesn't work. No scrollbar appears on the fluid item.
body {
margin: 0;
/* overflow: hidden; */
}
.page {
display: grid;
grid-template-rows: 55px auto;
grid-template-columns: 20vh auto;
grid-template-areas: "nav header"
"nav content";
}
.nav {
grid-area: nav;
background-color: aqua;
}
.header {
grid-area: header;
background-color: lightgrey;
}
.content {
grid-area: content;
height: 1000px;
overflow: auto;
background-color: red;
}
<div class="page">
<div class="nav">Side nav</div>
<div class="header">Header</div>
<div class="content">
<h1>title</h1>
</div>
<div>
You could target the row itself, as I tested:
.page {
display: grid;
grid-template-rows: 55px 1000px;
}
.content {
overflow: auto;
}
But that doesn't work either. Still no scrollbar on the fluid item.
body {
margin: 0;
/* overflow: hidden; */
}
.page {
display: grid;
grid-template-rows: 55px 1000px;
grid-template-columns: 20vh auto;
grid-template-areas:
"nav header"
"nav content";
}
.nav {
grid-area: nav;
background-color: aqua;
}
.header {
grid-area: header;
background-color: lightgrey;
}
.content {
overflow: auto;
grid-area: content;
background-color: red;
}
<div class="page">
<div class="nav">Side nav</div>
<div class="header">Header</div>
<div class="content">
<h1>title</h1>
</div>
<div>
So I targeted a child of the grid item. DING DING DING! That worked.
No need for fixed positioning. No need for sticky positioning. This works across all browsers that support Grid Layout.
body {
margin: 0;
}
.page {
display: grid;
grid-template-rows: 55px calc(100vh - 55px); /* height limitation on second row */
grid-template-columns: 20vh auto;
grid-template-areas: "nav header"
"nav content";
}
.nav {
grid-area: nav;
background-color: aqua;
}
.header {
grid-area: header;
background-color: lightgrey;
}
.content {
grid-area: content;
background-color: red;
overflow: auto; /* overflow condition on parent */
}
article {
height: 1000px; /* height set on child; triggers scroll */
}
<div class="page">
<div class="nav">Side nav</div>
<div class="header">Header</div>
<div class="content">
<article><!-- new section for content -->
<h1>title</h1>
</article>
</div>
<div>
jsFiddle demo
Browser support is not 100%, but what about actually using sticky instead of fixed positioning? (now tested in Chrome) You won't have to deal with hard-coded margins.
One of the issues you'll still have to deal with, what to do when the content in your sidebar (.nav > div) Is higher than your viewport.
body {
margin: 0;
}
.page {
display: grid;
grid-template-rows: 55px auto;
grid-template-columns: 3.5rem auto;
grid-template-areas: "nav header" "nav content";
}
.nav {
grid-area: nav;
background-color: blue;
}
.nav > div {
position: sticky;
top: 0;
}
.header {
grid-area: header;
background-color: grey;
position: sticky;
top: 0;
min-height: 3.5rem;
}
.content {
grid-area: content;
min-height: 1000px;
background-color: red;
}
<div class="page">
<div class="nav">
<div>Side nav</div>
</div>
<div class="header">Header</div>
<div class="content">
<h1>title</h1>
</div>
<div>
I have included the change log to see where the code needs to be change in order to get an understanding. Also the full code snippet is available below. Hope this is what you expect.
Change log
*Remove body { overflow: hidden; }
*Change .page { grid-template-columns: 3.5rem auto; }
*Added
.nav { position: fixed;
top: 0;
bottom:0;}
*Added
.header { position: fixed;
margin-left: 3.5rem;
width: 100%;
height: 3.5rem; }
Full Code
body {
margin: 0;
}
.page {
display: grid;
grid-template-rows: 55px auto;
grid-template-columns: 3.5rem auto;
grid-template-areas:
"nav header"
"nav content";
}
.nav {
position: fixed;
top: 0;
bottom:0;
grid-area: nav;
background-color: blue;
}
.header {
grid-area: header;
background-color: grey;
position: fixed;
margin-left: 3.5rem;
width: 100%;
height: 3.5rem;
}
.content {
grid-area: content;
height: 1000px;
background-color: red;
}
<div class="page">
<div class="nav">Side nav</div>
<div class="header">Header</div>
<div class="content">
<h1>title</h1>
</div>
<div>