Scrollbar with grid inside grid using css grids - html

I have a html page that I don't want to scroll at the body scope, however, when using css grids that are nested, I can't control the body's scrollbar when content inside a nested grid overflows even when it has the property to scroll on overflow. The snippet I provide below I have a container which has grid and it contains a grid-area called workspace which has a component that is also a css grid. The component has content that forces the whole body to scroll, where I only want the content to scroll. I try messing with heights to 100% and 100vh, but no such luck.
body, html {
margin: 0px;
}
.container {
background-color: #282828;
color: whitesmoke;
display: grid;
grid-template-columns: 1fr min-content;
grid-template-rows: 42px 1fr;
grid-template-areas:
'tabs sidebar'
'workspace sidebar';
height: 100vh;
}
.tabs {
grid-area: tabs;
background-color: violet;
}
.sidebar {
grid-area: sidebar;
background-color: tomato;
min-width: 50px;
}
.workspace {
grid-area: workspace;
background-color: blue;
}
.component {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: min-content 1fr;
grid-template-areas:
'header'
'content';
}
.header {
grid-area: header;
}
.content {
grid-area: content;
overflow-y: scroll;
}
<div class="container">
<div class="tabs">
</div>
<div class="sidebar">
</div>
<div class="workspace">
<div class="component">
<div class="header">
<h1>My header</h1>
</div>
<div class="content">
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
</div>
</div>
</div>
</div>

To have a scrollbar the container should have a height that if the content exceed then the scrollbar will be activated so whenever you want to have a scrollbar you have to keep in your mind that the border of your container should be defined some how.
Now with that being said, if you don't want to have a fixed height then the main div should be a full screen then the nested container can have a scroll otherwise it will keep growing.
the full screen because you don't want to provide any fixed height otherwise , if you have a fixed height then it will be more simple
body, html {
margin: 0px;
}
.container {
background-color: #282828;
color: whitesmoke;
display: grid;
grid-template-columns: 1fr min-content;
grid-template-rows: 42px 1fr;
grid-template-areas:
'tabs sidebar'
'workspace sidebar';
height: 100vh;
position:absolute;
left:0px;
right:0px;
top:0px;
bottom:0px;
}
.tabs {
grid-area: tabs;
background-color: violet;
}
.sidebar {
grid-area: sidebar;
background-color: tomato;
min-width: 50px;
}
.workspace {
grid-area: workspace;
background-color: blue;
position: relative;
overflow-y: hidden;
}
.component {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: min-content 1fr;
grid-template-areas:
'header'
'content';
}
.header {
grid-area: header;
}
.content {
grid-area: content;
overflow: auto;
position: absolute;
bottom: 0px;
right: 0px;
left: 0px;
top: 80px;
}
<div class="container">
<div class="tabs">
</div>
<div class="sidebar">
</div>
<div class="workspace">
<div class="component">
<div class="header">
<h1>My header</h1>
</div>
<div class="content">
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
<h1>Temp</h1>
</div>
</div>
</div>
</div>

Related

Make a div in a grid stretch to full height

I have a very simple grid layout of the menu, header, and content.
I would like the content (blue box) to stretch vertically. As you can see, the grid element (yellow box) already stretches vertically, but the blue element inside of it (which should be dynamic content) does not.
Is there a way to achieve this 1) without switching the whole grid structure to flexbox and 2) without using calc to give the blue content 100vh minus the header height?
.container {
height: 100vh;
display: grid;
grid-template-rows: min-content 1fr;
grid-template-columns: min-content 1fr;
grid-template-areas: "menu header" "menu content";
box-sizing: border-box;
overflow: hidden;
}
.mainMenuWrapper {
grid-area: menu;
height: auto;
}
.headerWrapper {
grid-area: header;
height: auto;
}
.contentWrapper {
grid-area: content;
overflow-y: auto;
height: auto;
background-color: yellow;
}
.menu {
height: 100vh;
background-color: red;
width: 50px;
}
.header {
height: 80px;
background-color: green;
}
.content {
background-color: blue;
width: 100%;
height: ???
}
<div class="container">
<div class="mainMenuWrapper">
<div class="menu">
menu
</div>
</div>
<div class="headerWrapper">
<div class="header">
header
</div>
</div>
<div class="contentWrapper">
<div class="content">
content
</div>
</div>
</div>
Image:
JSFiddle link: https://jsfiddle.net/the2sj1n/3/
You can apply height: 100% on that blue box .content
body {
margin: 0; /*Removed unexpected margins from browsers' default styles*/
}
.container {
height: 100vh;
display: grid;
grid-template-rows: min-content 1fr;
grid-template-columns: min-content 1fr;
grid-template-areas: "menu header" "menu content";
box-sizing: border-box;
overflow: hidden;
}
.mainMenuWrapper {
grid-area: menu;
height: auto;
}
.headerWrapper {
grid-area: header;
height: auto;
}
.contentWrapper {
grid-area: content;
overflow-y: auto;
height: auto;
background-color: yellow;
}
.menu {
height: 100vh;
background-color: red;
width: 50px;
}
.header {
height: 80px;
background-color: green;
}
.content {
background-color: blue;
width: 100%;
height: 100%; /*The change here*/
}
<div class="container">
<div class="mainMenuWrapper">
<div class="menu">
menu
</div>
</div>
<div class="headerWrapper">
<div class="header">
header
</div>
</div>
<div class="contentWrapper">
<div class="content">
content
</div>
</div>
</div>

How do I get rid of the space between the menu bar and the side nav?

How do I get rid of the space between the menu bar and the sidebar caused by typing hello.
I have tried
display:inline-block; and overflow:hidden; which got rid of the white space that was there previously and now filled it up with a color. I have also tried taking the content div and moving it so it isn't a parent(?) of .sidebar but then "hello" just ends up on the bottom of the page. I want to keep the "hello" text centered on the yellow area without having a space between the side bar and the menu bar.
Picture of the website
.menucontain{
display:grid;
grid-template-columns:1fr 1fr 1fr 1fr 1fr 1fr;
grid-column-gap:5px;
color:#F2F0D0;
text-align:center;
background-color:#204959;
font-family:helvetica;
padding:15px;
}
.sidebar{
background:#204959;
width:18%;
height:800px;
text-align:center;
color:#F2F0D0;
font-family:helvetica;
display:grid;
grid-template-rows: repeat(6 ,50px);
grid-gap:2px;
}
.side1{
background:gray;
padding-top:15px;
}
.content{
background-color:#F2F0D0;
text-align:center;
overflow:hidden;
}
<div class="menucontain">
<div class="menu1">Menu1</div>
<div class="menu2">Menu2</div>
<div class="menu3">Menu3</div>
<div class="menu4">Menu4</div>
<div class="menu5">Menu5</div>
<div class="menu6">Menu6</div>
<!--menu contain div on next line-->
</div>
<div class="content">
<p>hello</p>
<div class="sidebar">
<div class="side1">About</div>
<div class="side1">Blog</div>
<div class="side1">Sales</div>
<div class="side1">Partners</div>
<div class="side1">Portfolio</div>
<div class="side1">Contact</div>
</div>
</div>
Here is the correct solution to your problem.
First, move the tag <p> in sequence for sidebar. Like this:
...
<div class="sidebar">
<div class="side1">About</div>
<div class="side1">Blog</div>
<div class="side1">Sales</div>
<div class="side1">Partners</div>
<div class="side1">Portfolio</div>
<div class="side1">Contact</div>
</div>
<p>hello</p>
...
Secondly, assign the grid rules for the .content class by adding this to your css:
.content {
display: grid;
grid-template-columns: 18% 1fr;
}
And remove the width rules - width: 18% out of .sidebar selector. Because we defined the width as 18% in the grid rule above.
.menucontain {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
grid-column-gap: 5px;
color: #f2f0d0;
text-align: center;
background-color: #204959;
font-family: helvetica;
padding: 15px;
}
.content {
display: grid;
grid-template-columns: 18% 1fr;
}
.sidebar {
background: #204959;
/*width: 18%;*/
height: 800px;
text-align: center;
color: #f2f0d0;
font-family: helvetica;
display: grid;
grid-template-rows: repeat(6, 50px);
grid-gap: 2px;
}
.side1 {
background: gray;
padding-top: 15px;
}
.content {
background-color: #f2f0d0;
text-align: center;
overflow: hidden;
}
<div class="menucontain">
<div class="menu1">Menu1</div>
<div class="menu2">Menu2</div>
<div class="menu3">Menu3</div>
<div class="menu4">Menu4</div>
<div class="menu5">Menu5</div>
<div class="menu6">Menu6</div>
<!--menu contain div on next line-->
</div>
<div class="content">
<div class="sidebar">
<div class="side1">About</div>
<div class="side1">Blog</div>
<div class="side1">Sales</div>
<div class="side1">Partners</div>
<div class="side1">Portfolio</div>
<div class="side1">Contact</div>
</div>
<p>hello</p>
</div>
The p tag is a block element, to remove the space you have to remove hello <\p> from the 'content' class
Use flex display or grid display on the 'content' class
Re-aling the 3 different parts (menucontain, sidebar, content) into a grid by declaring the body as a grid. Sicne you already use grids to style the menucontain and sidebar, you have to switch them to a subgrid.
body {
margin: 0;
display: grid;
grid-template-columns: 18vw auto;
grid-template-rows: min-content auto;
min-height: 100vh;
}
.menucontain {
grid-column: span 2;
display: grid;
grid-template-columns: repeat(6, 1fr);
grid-template-rows: subgrid;
grid-column-gap: 5px;
color: #F2F0D0;
text-align: center;
background-color: #204959;
font-family: helvetica;
padding: 15px;
}
.sidebar {
background: #204959;
height: 800px;
text-align: center;
color: #F2F0D0;
font-family: helvetica;
display: grid;
grid-template-columns: subgrid;
grid-template-rows: repeat(6, 50px);
grid-gap: 2px;
}
.side1 {
background: gray;
padding-top: 15px;
}
.content {
background-color: #F2F0D0;
text-align: center;
overflow: hidden;
}
<div class="menucontain">
<div class="menu1">Menu1</div>
<div class="menu2">Menu2</div>
<div class="menu3">Menu3</div>
<div class="menu4">Menu4</div>
<div class="menu5">Menu5</div>
<div class="menu6">Menu6</div>
</div>
<div class="sidebar">
<div class="side1">About</div>
<div class="side1">Blog</div>
<div class="side1">Sales</div>
<div class="side1">Partners</div>
<div class="side1">Portfolio</div>
<div class="side1">Contact</div>
</div>
<div class="content">
<p>hello</p>
</div>

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>

Forcing a div to be full page height without using 100vh

This is a simplified HTML & CSS code to what I currently have in project. Essentially since I'm using ReactJS & routes, I can't wrap everything inside another container with a css grid so I'm looking for solutions to get full page height on both the 'sidebar' & 'content' classes.
I do understand that I could use 100vh and substract from that the height of the header but in this case the header doesn't have a fixed height so I'm looking for alternatives.
.header {
display: grid;
grid-template-columns: auto auto;
background-color: lightblue;
}
.main {
display: grid;
grid-template-columns: 0.2fr 1fr;
}
.sidebar {
background-color: lightpink;
height: 100%;
}
.content {
background-color: orange;
height: 100%;
}
<div class="header">
<div>
One
</div>
<div>
Two
</div>
</div>
<div class="main">
<div class="sidebar">
Menu
</div>
<div class="content">
Content
</div>
</div>
http://jsfiddle.net/de5ut6np/39/
You can consider the body as the main container:
html {
height:100%;
}
body {
margin:0;
height:100%;
display: grid;
grid-template-rows: max-content 1fr;
}
.header {
display: grid;
grid-template-columns: auto auto;
background-color: lightblue;
}
.main {
display: grid;
grid-template-columns: 0.2fr 1fr;
}
.sidebar {
background-color: lightpink;
height: 100%;
}
.content {
background-color: orange;
height: 100%;
}
<div class="header">
<div>
One<br>
more
</div>
<div>
Two
</div>
</div>
<div class="main">
<div class="sidebar">
Menu
</div>
<div class="content">
Content
</div>
</div>
I tested like this and it worked:
html {
height:100%;
}
body {
margin: 0;
height:100%;
display: grid;
grid-template-rows: max-content 1fr;
}
.header {
display: grid;
grid-template-columns: auto auto;
background-color: lightblue;
}
.main {
display: grid;
grid-template-columns: 0.2fr 1fr;
}
.sidebar {
display: grid;
background-color: lightpink;
}
.content {
display: grid;
background-color: orange;
}
<div class="header">
<div>
One
</div>
<div>
Two
</div>
</div>
<div class="main">
<div class="sidebar">
Menu
</div>
<div class="content">
Content
</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>