CSS Grid: Content to Use Free Space But Scroll When Bigger

CSS grid: content to use free space but scroll when bigger

You can use max-height:100%; and also min-height to leave enough heights to show a proper scrollbar.(firefox will do, chrome will not at this time)

.container {  display: grid;  grid-template-rows: auto minmax(1fr, 25vh) auto;  grid-template-columns: 1fr 1fr;}
.container>div { border: 1px solid blue; border-radius: 5px;}
.left { grid-column: 1; grid-row: 1/4;}
.header { grid-column: 2; grid-row: 1;}
.problem-child { grid-column: 2; grid-row: 2; min-height:4em; max-height:100%; overflow-y: auto;}
.footer { grid-column: 2; grid-row: 3;}
<div class="container">  <div class="left">left<br>I don't want this one to scroll<br>this should<br>determine<br>the height of the whole grid container</div>  <div class="header">column header</div>  <div class="problem-child">problem child:<br>I<br>want<br>this<br>to<br>scroll<br>rather<br>than<br>making<br>everything<br>tall</div>  <div class="footer">column footer</div></div>

Responsive CSS grid with scrollable cell overflows its parent container

A colleague of mine suggested to use the overflow-y: auto property on the grid container itself. While its effect is not exactly the same as I was looking for, it's very similar and it does prevent the sidebar content from overflowing the container. The only minor difference is that when the available space becomes smaller than the necessary minimum to display the content of the grid, it's the grid container that gets a vertical scroll bar instead of the viewport.

Below is the modified code snippet that demonstrates it.

* {
box-sizing: border-box;
}

body {
margin: 0;
}

ul {
list-style-type: none;
margin: 0;
padding: 0;
}

.bordered {
border-style: solid;
border-width: 5px;
}

/* grid layout */

.grid {
display: grid;
/* Default (small screen) layout. */
/* Single column with 3 rows, the last one filling out the remaining space. */
grid-template-rows: min-content min-content 1fr;
max-height: 100vh;
min-height: 100vh;
min-width: min-content;
overflow-y: auto; /* <-- the only property added to the original CSS */
}

@media (min-width: 640px) {
.grid {
/* Larger screen layout. */
/* 2 columns with 2 rows, the bottom right cell filling out the remaining space. */
grid-template-columns: max-content 1fr;
grid-template-rows: min-content 1fr;
}

nav {
grid-column: span 2 / span 2;
}
}

aside, nav {
white-space: nowrap;
}

main {
overflow-y: auto;
}
<html>

<body>
<div class="grid bordered" style="border-color: black;">
<nav class="bordered" style="border-color: green;">Top nav</nav>
<aside class="bordered" style="border-color: red;">
<ul>
<li>Some example sidebar item #1</li>
<li>Some example sidebar item #2</li>
<li>Some example sidebar item #3</li>
<li>Some example sidebar item #4</li>
<li>Some example sidebar item #5</li>
</ul>
</aside>
<main class="bordered" style="border-color: cyan;">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
<p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</main>
</div>
</body>

</html>

Prevent content from expanding grid items

By default, a grid item cannot be smaller than the size of its content.

Grid items have an initial size of min-width: auto and min-height: auto.

You can override this behavior by setting grid items to min-width: 0, min-height: 0 or overflow with any value other than visible.

From the spec:

6.6. Automatic Minimum Size of Grid
Items

To provide a more reasonable default minimum size for grid items, this
specification defines that the auto value of min-width / min-height also applies an automatic minimum size in the specified axis to grid items whose overflow is visible. (The effect is analogous to the automatic minimum size imposed on flex items.)

Here's a more detailed explanation covering flex items, but it applies to grid items, as well:

  • Why don't flex items shrink past content size?

This post also covers potential problems with nested containers and known rendering differences among major browsers.


To fix your layout, make these adjustments to your code:

.month-grid {
display: grid;
grid-template: repeat(6, 1fr) / repeat(7, 1fr);
background: #fff;
grid-gap: 2px;
min-height: 0; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}

.day-item {
padding: 10px;
background: #DFE7E7;
overflow: hidden; /* NEW */
min-width: 0; /* NEW; needed for Firefox */
}

jsFiddle demo



1fr vs minmax(0, 1fr)

The solution above operates at the grid item level. For a container level solution, see this post:

  • Who does minmax(0, 1fr) work for long elements while 1fr doesn't?

CSS Grid is larger than it's container div in height

This is being caused by the grid-gap. You're using grid-gap: 2%; which applies a % gap between both columns and rows. This works perfectly for the grid itself as we can see, and the grid is including the 2% gap between rows in it's total height.

However using percentages for height is problematic when the container doesn't have a defined height. What's happening here is that the container isn't recognising the % gap height and is not including it in it's total height.

You can easily fix it by using a defined value for height, e.g.

grid-column-gap: 2%;    // you can still use % for the column gap
grid-row-gap: 20px; // fixed height for row gap

Working Example:

.column {
margin-top: 3%;
margin-left: 20%;
margin-right: 20%;
background-color: rgba(200, 0, 0, 0.1);
}

.grid {
display: grid;
grid-template-columns: repeat( auto-fit, minmax(300px, 1fr));
grid-auto-rows: (0px, 1fr);
grid-column-gap: 2%;
grid-row-gap: 20px;
}

.plum {
/* background-color: plum; */
}

.card {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
border-radius: 10px;
background-color: rgba(0, 0, 0, 0.1);
}

.card:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}

.container {
padding: 2px 16px;
}

.container p {
word-wrap: break-word;
}

.centered {
text-align: center;
}
<body class="plum">
<br>
<div class="column">
<div class=" grid">
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: I like memes</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: I like memes again</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: this is a post</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: This is the first post from the website</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: I have added this</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: joe</p>
<p>Text: I'm joe</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: joe</p>
<p>Text: Okay</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: joe</p>
<p>Text: I like memes too</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: Caps test</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: OKAYYYYYYYYYYYYYYYYYYYYYYYY</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: sssssssssssssssssss</p>
</div>
</div>
<div class="card">
<div class="container">
<p>Poster: tester</p>
<p>Text: SSSSSSSSSSSSSSSSSS</p>
</div>
</div>
</div>
</div>
<p class="centered"><a href="submitform.php">Add new</a></p>

overflow scroll breaks in nested grid

You're right in the sense that there doesn't seem to be any reason why the scroll function works on one element (.aside), but not on another (.bottomleft). There doesn't appear to be any material difference. One element is a nested grid container. But that shouldn't matter.

However, if you look at the bigger picture, neither scrollbar should work.

The overflow property normally requires a fixed length to generate a scroll bar. Without such a limit, the element simply expands to accommodate content, and there's no possibility for an overflow.

Such is the case in your code: Both overflow elements are set to height: auto.

.container {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: auto auto; <-- second row (where 'aside' is placed) is
set to content-based height
grid-template-areas: 'nav nav ' 'aside main';
height: 100%;
}

.main-container {
display: grid;
grid-template-columns: 1fr 3fr;
grid-template-rows: auto auto; <-- second row (where 'bottomright' is placed) is
also set to content-based height
grid-template-areas: 'topleft topright' 'bottomleft bottomright';
height: 100%;
}

Now refer to this rule, as described in MDN:

In order for overflow to have an effect, the block-level container must have either a set height (height or max-height) or white-space set to nowrap.

Hence, the scroll function in your code should fail in both cases. The fact that one works in at least one browser suggests an anomaly or an intervention. In either case, I would suggest it's unreliable.

Consider a trade-off: Sacrifice some flexibility in return for more stability and security. Here is a modified version of your code:

revised fiddle

.container {  display: grid;  grid-template-columns: 1fr 3fr;  grid-template-rows: 25px calc(100vh - 25px); /* adjustment */  grid-template-areas: 'nav nav ' 'aside main';  height: 100vh;}
.header { grid-area: nav; background-color: lightblue;}
.main { grid-area: main; background-color: lightpink;}
.aside { grid-area: aside; overflow-y: scroll;}
.main-container { display: grid; grid-template-columns: 1fr 3fr; grid-template-rows: 25px calc(100vh - 50px); /* adjustment */ grid-template-areas: 'topleft topright' 'bottomleft bottomright';}
.topleft { grid-area: topleft;}
.topright { grid-area: topright;}
.bottomleft { grid-area: bottomleft; overflow-y: scroll;}
.bottomright { grid-area: bottomright;}
body { margin: 0; /* remove default margins */}
<div id="root">  <div class="container">    <div class="header">      header    </div>    <div class="main">      <div class="main-container">        <div class="topleft">          topleft        </div>        <div class="topright">          topright        </div>        <div class="bottomleft">          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>          <div>bottomleft</div>
<div>last</div>
</div> <div class="bottomright"> bottomright </div> </div> </div> <div class="aside"> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>aside</div> <div>last</div> </div> </div></div>


Related Topics



Leave a reply



Submit