make grid child scrollable when it's content is overflown - html

I'm trying to make the div with the class side-panel-content scrollable when it's content is big, overflow-y: scroll; doesn't work in this case.
The idea here, is to make the full page take the viewport, which works when the .long-content div has no height, but if it has a long height this shouldn't make it's container to grow more, and should be scrollable instead.
Here is a full example:
html, body {
height: 100%;
}
.main {
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
header, footer {
height: 80px;
background-color: yellow;
}
.content-wrapper {
height: 100%;
width: 100%;
display: grid;
grid-template-rows: auto 1fr;
}
.title {
padding: 24px;
width: 100%;
}
.main-content {
width: 100%;
display: grid;
gap: 24px;
grid-template-columns: 1fr 350px;
justify-content: space-around;
}
.main-panel {
display: grid;
grid-template-rows: auto 1fr;
border: 2px solid red;
}
.side-panel {
height: 100%;
width: 100%;
}
.side-panel-wrapper {
height: 100%;
background: #f8f9fa;
box-shadow: 0px 4px 10px rgb(0 0 0 / 10%);
display: grid;
grid-template-rows: auto 1fr;
}
.side-panel-header {
background-color: #ffffff;
padding: 24px;
border-bottom: 2px solid #e6e9f0;
}
.side-panel-content {
overflow-y: scroll;
}
.long-content {
height: 3000px;
}
<html>
<body>
<div class="main">
<header><h1>Header</h1></header>
<div class="content">
<div class="content-wrapper">
<div class="title">
<h1>Title</h1>
</div>
<div class="main-content">
<div class="main-panel">
<div>
<h2>
Main panel title
</h2>
<p>
Main panel content
</p>
</div>
</div>
<div class="side-panel">
<div class="side-panel-wrapper">
<div class="side-panel-header">
Side panel header
</div>
<div class="side-panel-content">
<div class="long-content">
long content
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer><h1>Footer</h1></footer>
</div>
</body>
</html>

The solution for this is to use an absolute positioning for the child div that has a long height.
html, body {
height: 100%;
}
.main {
height: 100%;
display: grid;
grid-template-rows: auto 1fr auto;
}
header, footer {
height: 80px;
background-color: yellow;
}
.content-wrapper {
height: 100%;
width: 100%;
display: grid;
grid-template-rows: auto 1fr;
}
.title {
padding: 24px;
width: 100%;
}
.main-content {
width: 100%;
display: grid;
gap: 24px;
grid-template-columns: 1fr 350px;
justify-content: space-around;
}
.main-panel {
display: grid;
grid-template-rows: auto 1fr;
border: 2px solid red;
}
.side-panel {
height: 100%;
width: 100%;
}
.side-panel-wrapper {
height: 100%;
background: #f8f9fa;
box-shadow: 0px 4px 10px rgb(0 0 0 / 10%);
display: grid;
grid-template-rows: auto 1fr;
}
.side-panel-header {
background-color: #ffffff;
padding: 24px;
border-bottom: 2px solid #e6e9f0;
}
.side-panel-content {
overflow: auto;
position: relative;
height: 100%;
}
.long-content {
position: absolute;
top: 0;
height: 3000px;
}
<html>
<body>
<div class="main">
<header><h1>Header</h1></header>
<div class="content">
<div class="content-wrapper">
<div class="title">
<h1>Title</h1>
</div>
<div class="main-content">
<div class="main-panel">
<div>
<h2>
Main panel title
</h2>
<p>
Main panel content
</p>
</div>
</div>
<div class="side-panel">
<div class="side-panel-wrapper">
<div class="side-panel-header">
Side panel header
</div>
<div class="side-panel-content">
<div class="long-content">
long content
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<footer><h1>Footer</h1></footer>
</div>
</body>
</html>

Related

How to make an element sticky but scrollable to its full (variable) height with sibling element?

I am trying to replicate the basic grid layout such as which is seen on Twitter. It seems to be working fine so far but I can't get the right sidebar to stop scrolling once it has scrolled to its full variable height.
In the image below the white space should not appear and once the element has scrolled to its full height it should stick.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
position: relative;
display: grid;
grid-template-columns: 1fr 3fr;
min-height: 100vh;
font-size: 2rem;
}
.inner-grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
}
.left-sidebar,
.right-sidebar,
.main {
margin: 0 1rem;
}
.left-sidebar,
.content {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.content {
height: 95%;
margin-top: 2.5rem;
}
.left-sidebar {
background-color: burlywood;
height: 100vh;
position: sticky;
top: 0;
}
.main {
background-color: tomato;
height: 1500px;
}
.right-sidebar {
background-color: cadetblue;
height: 900px;
}
.fixed-header {
background-color: black;
color: white;
position: fixed;
width: auto;
top: 0;
}
<div class="container">
<div class="left-sidebar">
<div>
<div>left sidebar</div>
<div>top</div>
</div>
<div>bottom</div>
</div>
<div class="inner-grid-container">
<div class="main">
<div class="fixed-header">fixed header</div>
<div class="content">
<div>
<div>main</div>
<div>top</div>
</div>
<div>bottom</div>
</div>
</div>
<div class="right-sidebar">
<div class="fixed-header">fixed header</div>
<div class="content">
<div>
<div>right sideabar</div>
<div>top</div>
</div>
<div>bottom</div>
</div>
</div>
</div>
</div>
Add
position: sticky;
bottom: 0;
margin-top: auto;
to the right sidebar
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
position: relative;
display: grid;
grid-template-columns: 1fr 3fr;
min-height: 100vh;
font-size: 2rem;
}
.inner-grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
}
.left-sidebar,
.right-sidebar,
.main {
margin: 0 1rem;
}
.left-sidebar,
.content {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.content {
height: 95%;
margin-top: 2.5rem;
}
.left-sidebar {
background-color: burlywood;
height: 100vh;
position: sticky;
top: 0;
}
.main {
background-color: tomato;
height: 1500px;
}
.right-sidebar {
background-color: cadetblue;
height: 900px;
position: sticky;
bottom: 0;
margin-top: auto;
}
.fixed-header {
background-color: black;
color: white;
position: fixed;
width: auto;
top: 0;
}
<div class="container">
<div class="left-sidebar">
<div>
<div>left sidebar</div>
<div>top</div>
</div>
<div>bottom</div>
</div>
<div class="inner-grid-container">
<div class="main">
<div class="fixed-header">fixed header</div>
<div class="content">
<div>
<div>main</div>
<div>top</div>
</div>
<div>bottom</div>
</div>
</div>
<div class="right-sidebar">
<div class="fixed-header">fixed header</div>
<div class="content">
<div>
<div>right sideabar</div>
<div>top</div>
</div>
<div>bottom</div>
</div>
</div>
</div>
</div>

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>

Display an overlay to fit parent when it is a grid area

I have a grid (containers) to display a navbar, a main-container and a footer. In the main-container, it is also a grid to display 3 children elements in a custom disposition using grid-area. Everything works properly.
Now, I would like to display an overlay div (overlay) which has to fit the whole main-container. To do so, I just add an additional div in the main-container with the property height: 100%; width: 100%; and play with the position property without success. Indeed, position: absolute or position: fixed make it too big and I don't want to set a fixed width or height since the layout can be responsive. And with position: relative, it is not working neither.
Do you have any idea, how I could make the overlay display above the main-container while keeping the properties width: 100%; height: 100%;?
#containers {
display: grid;
grid-template-areas: "navbar main" "navbar footer";
grid-template-rows: calc(100% - 32px) 32px;
grid-template-columns: 56px calc(100% - 56px);
}
#navbar-container {
grid-area: navbar;
background-color: blue;
}
#main-container {
grid-area: main;
height: 100%;
width: 100%;
display: grid;
grid-template-areas:
'child1 child2'
'child1 child3';
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
}
#footer-container {
grid-area: footer;
background-color: black;
}
#child1,
#child2,
#child3 {
padding: 10px;
}
#child1 {
grid-area: child1;
background-color: red;
}
#child2 {
grid-area: child2;
background-color: purple;
}
#child3 {
grid-area: child3;
background-color: pink;
}
#footer-container {
grid-area: footer;
}
.modal {
width: 100%;
height: 100%;
background-color: grey;
opacity: 0.5;
position: absolute;
}
<div id="containers">
<div id="navbar-container"></div>
<div id="main-container">
<div id="child1">
<span>CHILD 1</span>
</div>
<div id="child2">
<span>CHILD 2</span>
</div>
<div id="child3">
<span>CHILD 3</span>
</div>
<div class="modal">
MODAL
</div>
</div>
<div id="footer-container"></div>
</div>
Just needed to make the parent relative and the modal absolute.
#containers {
display: grid;
grid-template-areas: "navbar main" "navbar footer";
grid-template-rows: calc(100% - 32px) 32px;
grid-template-columns: 56px calc(100% - 56px);
}
#navbar-container {
grid-area: navbar;
background-color: blue;
}
#main-container {
grid-area: main;
height: 100%;
width: 100%;
display: grid;
grid-template-areas:
'child1 child2'
'child1 child3';
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr;
position: relative;
}
#footer-container {
grid-area: footer;
background-color: black;
}
#child1,
#child2,
#child3 {
padding: 10px;
}
#child1 {
grid-area: child1;
background-color: red;
}
#child2 {
grid-area: child2;
background-color: purple;
}
#child3 {
grid-area: child3;
background-color: pink;
}
#footer-container {
grid-area: footer;
}
.modal {
width: 100%;
height: 100%;
background-color: grey;
opacity: 0.5;
position: absolute;
}
<div id="containers">
<div id="navbar-container"></div>
<div id="main-container">
<div id="child1">
<span>CHILD 1</span>
</div>
<div id="child2">
<span>CHILD 2</span>
</div>
<div id="child3">
<span>CHILD 3</span>
</div>
<div class="modal">
MODAL
</div>
</div>
<div id="footer-container"></div>
</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>

css - nested div in grid does not respect grid sizes

So I'm trying to display cards within a grid. I would like the card size to be based on the grid size and then to overlay text on top of it that correctly matches the width.
Here's my implementation so far but it seems like the div/img no longer respects the grid's sizes
for (let i = 0; i < 15; i++)
{
$("#grid").append(`
<div class="item">
<div>
<img src="http://via.placeholder.com/250x350" />
<div class="text">
sadfsd
</div>
</div>
</div>
`);
}
.flex {
border: 1px solid black;
display: flex;
flex-direction: column;
height: 100vh;
}
.footer {
height: 20%;
}
.upper {
flex: 1;
overflow: auto;
}
#grid {
border: 1px solid black;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
height: 100%;
position: relative;
max-width: 100%;
box-sizing: border-box;
}
.item {
display: inline-block;
text-align: center;
position: relative;
}
.inner {
border: 1px solid red;
max-height: 100%;
max-width: 100%;
}
.text {
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
height: 30%;
border: 1px solid black;
width: 90%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="flex">
<div class='upper'>
<div id="grid">
</div>
</div>
<div class="footer">
footer
</div>
</div>
What I want is it to look something like this (of course with the text matching the width of the image)
for (let i = 0; i < 15; i++)
{
$("#grid").append(`
<div class="item">
<img src="http://via.placeholder.com/150x350" />
<div class="text">
text
</div>
</div>
`);
}
.flex {
border: 1px solid black;
display: flex;
flex-direction: column;
height: 100vh;
}
.footer {
height: 20%;
}
.upper {
flex: 1;
overflow: auto;
}
#grid {
border: 1px solid black;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
height: 100%;
position: relative;
max-width: 100%;
box-sizing: border-box; /* added */
}
.item {
position: relative;
}
.text {
border: 1px solid black;
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
width: 90%;
height: 30%;
}
img {
display: block;
margin: 0 auto;
max-height: 100%;
max-width: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
<div class="flex">
<div class='upper'>
<div id="grid">
</div>
</div>
<div class="footer">
footer
</div>
</div>