Add scroll to each column in CSS Grid Layout
Solution 1
In the landscape orientation I want to use 2 columns. My whole content is displayed on the left side and my navigation moves to the right side. Now I want both parts to have a separate scroll. Is there a way to implement this? And the scroll should stop if the content of the current column ends.
In the left column you have three separate grid items: the header
, main
and footer
elements.
In the right column you have one grid item: the nav
element.
Adding a scrollbar – vertical or horizontal – to the left column is not feasible because there are three separate elements. You would need to wrap all elements in a container for a single scrollbar to work.
Adding a scrollbar – vertical or horizontal – to the right column is pretty easy because there is only one element.
Assuming that you're talking about a vertical scrollbar, here's one way to make it work:
body {
margin: 0;
}
.grid-container {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
grid-gap: 15px 0;
height: 100vh;
}
header {
background-color: green;
grid-column: 1;
grid-row: 1
}
main {
background-color: blue;
grid-column: 1;
grid-row: 2;
}
nav {
background-color: pink;
grid-column: 1;
grid-row: 3;
overflow: auto;
}
footer {
background-color: teal;
grid-column: 1;
grid-row: 4;
}
@media only screen and (orientation: landscape) {
.grid-container {
grid-template-columns: 5fr 4fr;
grid-template-rows: 1fr 1fr 1fr;
}
nav {
grid-column: 2;
grid-row: 1 / span 3;
}
footer {
grid-row: 3;
}
}
<div class="grid-container">
<header>
<h1>Logo</h1>
</header>
<main>
<h1>content</h1>
</main>
<nav>
<h1>Navigation<br><br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br>nav item<br></h1>
</nav>
<footer>
<h1>Footer</h1>
</footer>
</div>
Browser Support for CSS Grid
- Chrome - full support as of March 8, 2017 (version 57)
- Firefox - full support as of March 6, 2017 (version 52)
- Safari - full support as of March 26, 2017 (version 10.1)
- Edge - full support as of October 16, 2017 (version 16)
- IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Solution 2
Here is a extended version from my answer on your earlier question, how to get scroll for both header/content/main and nav using flexbox
.
Stack snippet
(function(w, d, timeout) {
w.addEventListener("load", function() {
resizer();
}, false);
w.addEventListener("resize", function() {
if (!timeout) {
timeout = setTimeout(function() {
timeout = null;
// do resize stuff
resizer();
}, 66);
}
}, false);
function resizer() {
if (w.innerHeight < w.innerWidth) {
if (!(d.body.classList.contains('landscape'))) {
d.body.classList.add('landscape');
d.body.appendChild(d.querySelector('nav'));
}
} else {
if (d.body.classList.contains('landscape')) {
d.body.classList.remove('landscape')
d.querySelector('section').appendChild(d.querySelector('nav'));
}
}
}
}(window, document));
html, body {
margin:0;
}
header, footer, main, nav {
margin: 5px;
padding: 5px;
border-radius: 5px;
min-height: 120px;
border: 1px solid #eebb55;
background: #ffeebb;
}
footer {
order: 2;
}
nav {
order: 1;
}
section {
display: flex;
flex-direction: column;
}
@media only screen and (orientation: landscape) {
main div {
height: 400px;
border: 1px dashed red;
}
nav div {
height: 800px;
border: 1px dashed red;
}
body.landscape {
display: flex;
}
section {
display: block;
width: calc(60% - 10px); /* 10px is for the margin */
box-sizing: border-box;
max-height: calc(100vh - 20px);
overflow: auto;
}
nav {
width: calc(40% - 10px); /* 10px is for the margin */
box-sizing: border-box;
max-height: calc(100vh - 20px);
overflow: auto;
}
}
<section>
<header>header</header>
<main>content
<div>
This div get a height when in landscape to show scroll in section
</div>
</main>
<footer>footer</footer>
<nav>navigation
<div>
This div get a height when in landscape to show scroll in nav
</div>
</nav>
</section>
Comments
-
ruslansteiger almost 2 years
I want separate scroll on each of my columns in my grid layout.
Currently, I am developing a mobile only web application. I want to use a different grid layout for the portrait and landscape orientations.
The portrait orientation is just 1 column and every element is after the other. No problem here.
In the landscape orientation I want to use 2 columns. My whole content is displayed on the left side and my navigation moves to the right side. Now I want both parts to have a separate scroll. Is there a way to implement this? And the scroll should stop if the content of the current column ends.
Code on CodePen: https://codepen.io/SuddenlyRust/pen/rmJOqV
.grid-container { display: grid; grid-template-columns: 1fr; grid-template-rows: 1fr; grid-gap: 15px 0; } header { background-color: green; grid-column: 1; grid-row: 1 } main { background-color: blue; grid-column: 1; grid-row: 2; } nav { background-color: pink; grid-column: 1; grid-row: 3; } footer { background-color: teal; grid-column: 1; grid-row: 4; } @media only screen and (orientation: landscape) { .grid-container { grid-template-columns: 5fr 4fr; } nav { grid-column: 2; grid-row: 1 / span 3; } footer { grid-row: 3; } } h1 { min-height: 200px; }
<div class="grid-container"> <header> <h1>Logo</h1> </header> <main> <h1>content</h1> </main> <nav> <h1>Navigation</h1> </nav> <footer> <h1>Footer</h1> </footer> </div>
Thank you very much for your time!
-
ruslansteiger about 7 yearsThank you very much @Michael_B for your time. But this solution only works if the navigation is bigger then the left content. My Navigation just takes half the space of the left content. I am not sure if this really works well with grid layouts.
-
ruslansteiger about 7 yearsNearly works. But if I scroll on the left side my navigation disappears. Is there a way to wrap the left content together?
-
Michael Benjamin about 7 yearsIf you can wrap the left elements in one container, then everything gets a lot easier. Just use flexbox. codepen.io/anon/pen/jmZgEo?editors=1100
-
ruslansteiger about 7 yearsYeah thank you. That was my next idea to use flex. Looks like grid is not suited for my solution! Thank you very much for your time @Michael_B you helped alot ;)
-
ruslansteiger about 7 yearsYeah nice job @LGSon. This works perfect. Could I ask you some basic question. I am not that skilled in javascript. What does the first and last part actually do? "(function(d, timeout) {" and "}(document));" You are using the variable d always to manipulate the dom but how is it defined? I don't understand the syntax. And I don't get the timeout variable. Looks like magic to me. The code does make sense how you move the nav part around the tree.
-
Asons about 7 years@SuddenlyRust The
(function(d, timeout) {...})();
calls a closure and wrap what's in it so it does not pollute the global scope with variables and stuff. It executes itself with the last(document)
and wheredocument
(the DOM's document) is passed in as the first parameterd
. I did this so instead of writingdocument.body
etc, I can use the shorterd.body
. Thetimeout
is used in the resize event and since it is passed in like that, as a parameter, it is accessible through out the entire closure function, just like a global variable is. Hope this make sense. -
ruslansteiger about 7 yearsyeah wow thanks. so much to learn ;) really appreatice your time. have a great day mate. I am gonna rewrite it in jQuery haha. so I can understand it much easier. But I think I can use your solution. it works perfectly fine
-
Asons about 7 years@SuddenlyRust I recommend to not rewrite the resize handler part and use jQuery resize event, because it does not have the throttler functionality mine has, unless you add the equivalent plug-in of course. What I provided with plain javascript has the less impact as possible on performance and there is no real reason to jQuery-fy it.
-
ruslansteiger about 7 yearsprobably I could just remove jQuery in my current project and try to rewrite everything in plain javascript. How would you rewrite following in plain JS? codepen.io/SuddenlyRust/pen/JNaygY?editors=0010# It would be a bit complicated or? Not sure how to add the 'one' handler with animationend
-
Asons about 7 years@SuddenlyRust With something like this: codepen.io/anon/pen/PmdJGR ... though it is perfectly fine to use both jQuery and plain javascript. About animation events, here is a good article: sitepoint.com/css3-animation-javascript-event-handlers