auto-fit and minmax() don't work inside nested grid - css

I have two nested grids - one for the layout and one for the part of my site (let's say it's a list of goods in the shop). My layout grid creates a container for the whole site, including navbar, sidebar, content, etc. And nested grid is responsible for the list of goods only. The problem is that auto-fit and minmax functions don't work in the nested grid. You can check this pen to see the case.
At first, try to change width of the content, you'll see that items are changing its position according to the auto-fit algorithm. But as soon as you uncomment display: grid; for the outer grid, it responsiveness gets broken. Could you please explain why this is happening and how I can fix it?
.outer-grid {
/* display: grid; */
grid-template-columns: 1fr 700px 1fr;
}
.inner-grid {
grid-column: 2;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.item {
background: red;
border: 1px solid black;
}
<div class="outer-grid">
<div class="inner-grid">
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
</div>
</div>

The problem is that auto-fit and minmax functions don't work in the nested grid.
I think they do work. The problem appears to be something else.
Your nested grid exists in a column with a fixed width (700px). The primary container sees no reason to shrink that column, which would trigger the auto-fit function in the nested grid.
Here's something you may want to consider:
revised codepen
.outer-grid {
display: grid;
grid-template-columns: 1fr repeat(1, minmax(100px, 700px)) 1fr;
}
.inner-grid {
grid-column: 2;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.item {
background: red;
border: 1px solid black;
}
<div class="outer-grid">
<div class="inner-grid">
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
</div>
</div>

Related

Grid is not sizing correctly in row direction

Background
I am trying to build a page with main section containing a dynamic grid in between a header and footer. As users use the page, book shaped .grid-item divs are appended to the .grid. Initially, when the .grid is empty, I want the <main> to expand to fill the page space so the footer isn't floating half way up the page. As the grid grows beyond the confines of this space, I want the page to grow vertically so that it scrolls.
Book shape
By book shaped, I mean that the column should be 2/3 the size of the height for each grid item.
Problem
The problem is that only the columns of the grid are behaving as intended with the items equally sized. In the row direction, only the first row is working as intended and the following rows are only the height of the content. As a result, they are no longer book shaped.
Solutions tried
I added flex: 1 to the <main> so that it can grow as needed. I also used grid-template-rows: repeat(auto-fill, minmax(300px, 1fr)); so that it would auto-fill the grid with equally sized rows.
Following this, I tried to auto-fill the grid with static sized columns and rows:
grid-template-columns: repeat(auto-fill, 200px);
grid-template-rows: repeat(auto-fill, 300px);
After this, I did some reading on the repeat() function and auto-fill to see where my misunderstanding is. I also searched stack-overflow for similar issues and attempted some mentioned solutions like changing my flex-grow and flex-basis for the <main> but I could not resolve the issue.
Closest Solution
I found that if I change the rows explicitly instead of using auto-fill, then the rows work as intended.
grid-template-rows: repeat(12, minmax(250px, 1fr));
This would however require for me to use javascript to change the styling of the .grid as I append children. This solution doesn't work because if the page width changes so that there are fewer columns, the rows would increase automatically, so it would add a lot of extra work to calculate the required rows using javascript before changing the styling. For this reason, I am ideally looking for a CSS only solution.
body {
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
margin: 0;
padding: 0;
}
header, footer {
height: 40px;
}
main {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
background-color: grey;
width: 100%;
}
.grid {
display: grid;
width: 60vw;
margin: 5px var(--margin-size) 5px var(--margin-size);
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: repeat(auto-fill, minmax(300px, 1fr));
gap: 10px;
}
.grid-item {
background-color: red;
}
<body>
<header>
Header
</header>
<main>
<div class="grid">
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
</div>
</main>
<footer>
Footer
</footer>
<body>
My question is how can I make the grid grow beyond the confines of the screen while retaining the book shape of the grid children?
I was able to get it working as intended with:
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: minmax(300px, 1fr);
Working snippet below:
body {
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
margin: 0;
padding: 0;
}
header, footer {
height: 40px;
}
main {
flex: 1;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
background-color: grey;
width: 100%;
}
.grid {
display: grid;
width: 60vw;
margin: 5px var(--margin-size) 5px var(--margin-size);
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-rows: minmax(300px, 1fr);
gap: 10px;
}
.grid-item {
background-color: red;
}
<body>
<header>
Header
</header>
<main>
<div class="grid">
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
<div class="grid-item">
Grid Item
</div>
</div>
</main>
<footer>
Footer
</footer>
<body>

Having a "display: inline-block" as a parent to a "display: grid" element without having text overlap?

I'm trying to arrange a set of statistics such that:
they are displayed on a single horizontal line
the enclosing element is no wider than it needs to be to contain the content
there should be a fixed gap between statistics
I tried implementing this using display: grid. Here is my approach:
.outer {
background-color: yellow;
display: inline-block;
}
.stats {
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}
<div class="outer">
<div class="stats">
<div class="stat">
<strong>Value:</strong> 1,234,568
</div>
<div class="stat">
<strong>Another value:</strong> 98,765
</div>
<div class="stat">
<strong>Test value:</strong> 83,263
</div>
</div>
</div>
Unfortunately, this results in some strange overlapping. Despite there being plenty of room for the .outer element to expand, the statistics are wrapped over several lines and the text runs into other columns:
How can I avoid this problem? I tried adding:
.stat {
white-space: nowrap;
}
...but the text still "runs" together. What am I missing?
The main problem stems from this declaration:
grid-template-columns: repeat(auto-fit, minmax(0, 1fr))
You're setting the columns to shrink to zero width.
Also, 1fr does nothing here, because there is no free space in the container. (You have the primary container set to inline-block, i.e., min-width. This means no extra space.)
At a minimum, these commands appear to be confusing the inline-block algorithm.
Consider leaving the columns at auto width (a default setting).
And, perhaps, setting them to appear in the first row. (I used the grid-auto-flow: column technique.)
.outer {
background-color: yellow;
display: inline-block;
}
.stats {
display: grid;
grid-gap: 20px;
grid-auto-flow: column;
}
<div class="outer">
<div class="stats">
<div class="stat">
<strong>Value:</strong> 1,234,568
</div>
<div class="stat">
<strong>Another value:</strong> 98,765
</div>
<div class="stat">
<strong>Test value:</strong> 83,263
</div>
</div>
</div>

Can't work out how to align logo and nav in a row using CSS grid

I'm trying to align a logo and navigation bar in one row across the top of a website using CSS grid.
I've written out the code but can't work out what I'm doing wrong as to why it's not working: https://codepen.io/chloewb/pen/wRRewQ
.logo{
grid-area: logo;
background:white;}
.navi{
grid-area: navi;
background:Yellow;}
.section1{
grid-area: features;
background:LightSalmon;}
.section2{
grid-area: technology;
background:PaleTurquoise;}
.section3{
grid-area: pricing;
background:LightPink;}
.section4{
grid-area: email;
background:PaleGreen;}
.container {
display: grid;
grid-template-rows: repeat (5, auto);
grid-template-columns: 1fr 1fr 1fr;
font-size: 40px;
width: 100%;
background: grey;
grid-template-areas:
"logo navi navi"
"features features features"
"technology technology technology"
"pricing pricing pricing"
"email email email";}
The first thing to notice is that, when you use display: grid on a container element, its direct children will become grid-items, and to these items is that the grid layout you build will apply.
So let's say we have the following:
<div class="container">
<div class="child-1">
<div class="child-2"></div>
<div class="child-2"></div>
</div>
<div class="child-1"></div>
<div class="child-1"></div>
<div class="child-1"></div>
</div>
And this CSS:
.container{
display: grid;
}
Then only the child-1 will become grid items and be able to get properties like grid-area applied to them; everything else inside .child-1, like .child-2 will behave normally, as if there's no Grid. Unless you also specify the .child-1 element to be a grid with display: grid.
In your case, you header element is a direct child of the .container element, so it is a grid item and can be positioned on any place on the grid, but the logo and navi elements are children of header, so the grid layout does not apply to them. You would either have to take them out of the header so the rules you wrote take effect, or create another grid in the header and let it use the full first row. See this example and notice how the nesting of the elements affect them.
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: minmax(50px, auto);
grid-template-areas: "logo navi navi";
margin-bottom: 20px;
border: 1px solid black;
}
.logo {
border: 1px solid red;
grid-area: logo;
}
.navi {
border: 1px solid blue;
grid-area: navi;
}
<div class="container">
<div class="logo">Logo</div>
<div class="navi">Nav</div>
</div>
<div class="container">
<header>
<div class="logo">Logo</div>
<div class="navi">Nav</div>
</header>
</div>

CSS grid column centering [duplicate]

With a flex container and flex-wrap: wrap set you can align overflowing items to the center using justify-content: center.
Is there a way to achieve the same behaviour for overflowing grid items using CSS grid?
I've created a pen showing the desired flex behavior
.container-flex {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.container-flex .item {
width: 33.33%;
background: green;
border: 1px solid;
}
.container-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.container-grid .item {
background: red;
border: 1px solid;
}
* {
box-sizing: border-box;
}
<h3>Flex</h3>
<div class="container-flex">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>
<h3>Grid</h3>
<div class="container-grid">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
</div>
https://codepen.io/JoeHastings/pen/PeEjjR
Flex and Grid are different animals, so a behavior that's simple in flex may not translate well to grid.
A flex item can center across the container because flex layout works with flex lines. A flex line is a row or column.
When a flex item is asked to center in a row/column, it has access to the available space on the entire line, from beginning to end.
In grid layout, however, rows and columns have to contend with something that flex lines don't: track walls (a/k/a grid lines). For example, in your code there are three columns. These columns divide the track into three separate sections, and grid items are confined to a section.
Therefore, a grid item cannot automatically be centered on a row using keyword alignment properties (such as justify-content or justify-self) because the track walls restrict movement.
It is possible to make a grid area span the entire row/column, which then clears the way across the entire track, allowing a grid item to be centered horizontally (justify-content: center) or vertically (align-self: center), but this behavior must be explicitly defined.
For the grid item to be centered across the row in a dynamic layout the container would need to have only one column (i.e., no dividers), or the item would need to be explicitly moved to the center using something like line-based placement. Otherwise, use flexbox.
Not the way you want with flex. You have to be precise with CSS-Grid,
<h3>Grid</h3>
<div class="container-grid">
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item">item</div>
<div class="item-mid">item</div>
</div>
.container-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.item {
background: red;
border: 1px solid;
}
.item-mid{
background:purple;
grid-column:2/1;
}
Also, look here,
Centering in CSS Grid
(this is not wrapping, however)
Late to this party. But at least in 3 grid row scenarios like this you can use a mixture of :nth-of-type and :last-of-type to target the trailing item and place it in the column. Kind of piggy backing off of the answer above you get:
.container-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
.item {
background: red;
border: 1px solid;
}
/* target the last item, if its the only one in the row */
.item:last-of-type:nth-of-type(3n+1) {
background:purple;
grid-column:2;
}
This, unfortunately, doesn't scale out super well to any other row count due to the problems listed in the above answers, but maybe will help someone.

How to repeat grid-template-rows for all rows

I'm trying create template for rows in my grid block:
grid-template-rows: repeat(3, 150px);
I know, this template should be work for first 3 rows.
However, from 4 row this template is not work.
Can i make template for all rows?
P.S.
This template work only for 1st row.
grid-template-rows: 150px;
Use grid-auto-rows (automatically generated rows) instead of grid-template-rows (manually generated rows). In current case grid-auto-rows: 150px will do the trick. Demo:
.grid {
display: grid;
grid-auto-rows: 150px;
/* space between columns for demo */
grid-gap: 10px;
}
/* just styles for demo */
.grid__item {
background-color: tomato;
color: white;
}
<div class="grid">
<div class="grid__item">One</div>
<div class="grid__item">Two</div>
<div class="grid__item">Three</div>
<div class="grid__item">Four</div>
<div class="grid__item">Five</div>
<div class="grid__item">Six</div>
<div class="grid__item">Seven</div>
<div class="grid__item">Eight</div>
<div class="grid__item">Nine</div>
</div>

Resources