CSS grid row overflows its container vertically - html

I would like to have a grid layout on a page where the grid stretches out to the entire viewport, and the rows have a minimum height. The simplest example would be a grid with a single cell (see code snippet below).
The problem I am having is that when the height of the viewport is less than the defined minimum row-height, the row vertically overflows its container. With the added red and green borders in the below example it's visible that the row's height isn't going below the defined 500 pixels, but the grid-container is still sized to the viewport which is now shorter than 500 pixels.
If I remove the height CSS attribute from the grid class, the container doesn't shrink below its content, but it also doesn't fill out the vertical space when the viewport is taller than 500 pixels. Since I want the grid to fill the entire page, I need the height CSS attribute. I've also added the min-height: fit-content attribute which is supposed to prevent the used value of the height property from becoming smaller than the value specified for min-height but it doesn't work (not with the defined fit-content value - it works as expected with an exact value, for example 300px).
In a similar question the culprit was the percentage values used for the gaps, but in this case there is nothing relatively sized. Even if replace the grid-template-rows: minmax(500px, 1fr); property with the fixed grid-template-rows: 500px;, it still behaves the same way.
body {
margin: 0;
}
.grid {
display: grid;
grid-template-rows: minmax(500px, 1fr);
height: 100vh;
min-height: fit-content;
width: 100vw;
}
.bordered {
border: 10px solid green;
}
<div class="grid bordered" style="border-color: red;">
<div class="bordered">Some content</div>
</div>
What I would like to have is a grid that fills out the entire viewport and where the grid-container is never smaller than its content. What am I missing?

Something to know is that as soon as a min height of a row, or the combined height of multiple rows, is greater than the height of the viewport, you will have a scroll. Beyond that, the snippet below, I hope does what you are looking for. I added comments in the code.
/* lines I added */
*{
box-sizing: border-box;
}
body {
margin: 0;
}
.grid {
display: grid;
/* 100 is for the small viewport here in the code snippet */
grid-template-rows: repeat(auto-fit, minmax(100px, 1fr));
min-height : 100vh;
}
.bordered {
border: 10px solid green;
}
<div class="grid bordered" style="border-color: red;">
<div class="bordered">Some content</div>
</div>

Related

How to make grid elements take up exactly 1/2 of the screen?

I am trying to make a website that utilizes grid elements to show the reader information about the different items (in my case I am doing them about planets). I, not well versed in CSS, am puzzled about how to make them take up an exact percentage of the screen. When I make the elements scale to screen, it makes the columns very very small.
/* Apply styles to the grid container */
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 10px;
padding: 20px;
}
/* Apply styles to the grid items */
.grid-item {
background-color: #7a6767;
border: 1px solid #5e4e4e;
padding: 20px;
}
<div id="saturn" class="grid-item">
<h1>Saturn Description!</h1>
<h2>SATURN!</h2>
</div>
<div id="uranus" class="grid-item">
<h1>Uranus Description!</h1>
<h2>URANUS!</h2>
</div>
<div id="neptune" class="grid-item">
<h1>Neptune Description!</h1>
<h2>NEPTUNE!</h2>
</div>
You can add width: 50%; on your grid-item class and then it should ocupate exactly 1/2 of the screen. If you want to get rid of the gap between edge of the screen and your elements, you need to add margin: 0; property on your body element.
As mentioned above, add the property width: 50% so that it occupies half of the screen and automatically adjusts to the screen size, and if you want it to be centered you can use a margin: 0 auto; applied to the parent div.
Or, as an option, besides % you can use vw (viewport width).
Here it is live, in the sandbox: https://playcode.io/1198023
To make grid elements take up exactly 1/2 of the screen, you can set the grid-template-columns property of the grid container to have two equal-width columns, using the fr unit. For example, you can set it to grid-template-columns: 1fr 1fr;.
Here's an updated code snippet:
/* Apply styles to the grid container */
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 10px;
padding: 20px;
}
/* Apply styles to the grid items */
.grid-item {
background-color: #7a6767;
border: 1px solid #5e4e4e;
padding: 20px;
}
Note that this will give each grid item an equal width of 50% of the screen, regardless of the screen size. If you want to control the width of the grid items relative to the screen size, you can use media queries to adjust the grid-template-columns property at different screen sizes. For example, you can set it to grid-template-columns: 1fr for screens smaller than a certain width, and to grid-template-columns: 1fr 1fr for larger screens.

Overflow works on outer 100% height div but not inner 100% height div

I have a CSS grid with a row div for a header, a row div for content, and a row div for a footer. I want the content to fill the screen but keep the header and footer visible. I have a fixed-size div inside another div inside the content div. Everything except the fixed-size div is height: 100%.
If I apply overflow-y: auto to the content div, the scrollbar appears on the content div. This is great, but what I really want is for the scrollbar to appear on the div inside the content div instead.
https://jsfiddle.net/efth2akr/2/
If I apply overflow-y: auto to the div inside the content div instead, there is no scrollbar and the content div takes on the height of the fixed-size div. This pushes the footer down and puts a scrollbar on the whole page. What?? Isn't height: 100% supposed to be based on the parent height? Other questions that describe similar scenarios fail to put height: 100% all the way up the chain, but I haven't.
https://jsfiddle.net/t08u9wnk/2/
How can I achieve my desired behavior of having the scrollbar appear on the div inside the content div while maintaining a responsive layout? What am I not understanding about height: 100% in this scenario?
Browser: Microsoft Edge 103.0.1264.62
I think the approach you are trying to follow would work only if you set a fixed height or max-height to div.grid-content > div. Now the problem is that the height of this container is dynamic and depends on height: 100%, so you might be tempted to do max-height: 100% but here is a good reason for why this is not possible.
If you want div.grid-content > div to have a scroll and keep the layout of the entire page based on the height of the screen, I'd propose you to use an absolute positioned overlay.
Here is a modified snippet of your code explaining how it works:
html, body {
height: 100%;
width: 100%;
}
body {
/* prevents scroll on the entire page */
overflow: hidden;
}
*, *::before, *::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
div.grid {
display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: 1fr;
height: 100%;
width: 100%;
}
div.grid-header, div.grid-footer {
background-color: #ff0000;
}
div.grid-content {
background-color: #00ff00;
/* set relative positioning to contain absolute child */
position: relative;
}
div.grid-content > div {
/* this is strategy for creating a container that adapts to the size of its relative parent using absolute positioning without the need of setting a fixed height to div.grid-content */
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
/* add scroll on y axis */
overflow-y: auto;
}
div.grid-content > div > div {
height: 200vh;
width: 50%;
background-color: #0000ff;
}
<div class="grid">
<div class="grid-header">
<h3>
hi
</h3>
</div>
<div class="grid-content">
<div>
<div>
asdf
</div>
</div>
</div>
<div class="grid-footer">
<h3>
bye
</h3>
</div>
</div>
I have been bitten by this unintuitive design choice of CSS grid: https://github.com/w3c/csswg-drafts/issues/1777
In summary, CSS grid "1fr" behaves like minmax(auto, 1fr) (where 1fr is the actual fractional dimension of the grid). The minimum width/height of a "1fr" grid row/column is the auto width/height. If the auto width/height is larger than 1fr, the whole row/column will expand out past 1fr because minmax ignores the max when min > max!
This is why my problem has the same symptoms as all the other questions about height: 100% not working where the answer was that they had an ancestor with height: auto. It turns out 1fr can become auto!
Replacing:
grid-template-rows: auto 1fr auto;
with:
grid-template-rows: auto minmax(0, 1fr) auto;
fixes the problem.
https://jsfiddle.net/t08u9wnk/3/

Set the grid container div width by the width of one of it's rows

I have a layout that looks like this:
<div class="container">
<div class="input"></div>
<div class="filter buttons"></div>
<div class="content"></div>
</div>
And this is their styling:
.container {
display: grid;
grid-row-gap: 30px;
padding: 30px 15px;
}
.input {
max-width: 350px;
}
.filter-buttons {
display: grid;
grid-template-columns: repeat( auto-fit, 170px);
grid-gap: 10px;
}
You can see the codesanbox here. What I would like is to have the container width set by the width of the row with filter buttons. I can't have it fixed, since filter buttons have auto wrapping set with auto-fit. And since content takes the full width, the containers width is set by the content width.
What I am trying to achieve is to have a responsive layout with css grid and without having to use media queries, where container would follow the width of filter_buttons div.
So, it would look like this on the small screens:
And like this on bigger screens:
How can I achieve that kind of layout?

CSS - Set element's max-width as a multiple of min-content

TLDR; I can set the max-width of an element to min-content, but I how can I set it to min-content * n?
I have an element with dynamically determined content inside a container. The page is viewed on a wide viewport (viewport width > table's min-width). Something like this:
<section class="container">
<div class="data"><!-- Some content here --></div>
</section>
.container {
display: grid;
justify-items: center;
justify-content: stretch;
}
.data {
min-width: min-content;
}
I would like the div to stretch in width, but only to an extent. Again, the content of the div is dynamically determined, so I cannot set a fixed value for max-width. Therefore I would like to set its max-width to be a multiple of its min-width, something like this:
.data {
min-width: min-content;
max-width: calc(min-content * 1.5);
}
Obviously I cannot do this because min-content is a named property value, not a resolvable number. So how should I achieve this in CSS only? Or am I obliged to use JS? Thanks in advance.

How do I remove extra height produced by hidden overflown child?

I have a parent grid container with 2 columns. In the first column, I have multiple panels which expands the height of the parent container if opened. In the second column, I have a component which expands more than the parent container's initial height.
What I want is for the second column to expand its height based on the height of the parent container.
It currently works however, it produces extra height and an empty space underneath my content.
I have tried giving the second column a fixed height instead of using calc(). Which works, space is removed but it no longer expands. I'm unsure what my other options are.
// .scss
.parent-container {
display: grid;
grid-template-columns: 60% 1fr;
grid-column-gap: 1rem;
}
.first-column {
width: 1fr;
}
.second-column {
width: 1fr;
max-height: calc(100% - 400px);
overflow: auto;
padding-bottom: 2rem;
}
// .html
<div class="parent-container">
<form class="first-column">
<!-- Angular Material Components -->
</form>
<div class="second-column">
<product-demo></product-demo>
</div>
</div>