CSS Scrollable aspect-ratio - css

I have a display: grid div that contains elements.
These elements should be placed automatically as rows of elements, with a 1 / 1 aspect ratio so the parent should be scrollable.
Let's say I have 32 items, and I want them to show as 4 row of 8 items.
The items' width are shrinked to not overflow the parent, but I want them to overflow if needed.
Here is the parent CSS :
display: grid;
gap: 10px;
padding: 20px;
grid-auto-flow: column;
grid-template-rows: repeat(4, 1fr);
and the items CSS
aspect-ratio: 1 / 1;
It works just well if I explicitly add width or height to the children, but I want them to grow automatically.
CodePen : https://codepen.io/dbenfouzari/pen/GRmdVze?editors=1100
Try to resize the window to a smaller width to see it no working.
Thanks !

Thanks to #G-Cyrillus answer, I finally get it to work simply by adding overflow: auto; on the parent wrapper and min-width: max-content; on each child !

Related

Image overflows fixed size grid in Chrome when image spans entire grid and grid-template-row is 1fr [duplicate]

TL;DR: Is there anything like table-layout: fixed for CSS grids?
I tried to create a year-view calendar with a big 4x3 grid for the months and therein nested 7x6 grids for the days.
The calendar should fill the page, so the year grid container gets a width and height of 100% each.
.year-grid {
width: 100%;
height: 100%;
display: grid;
grid-template: repeat(3, 1fr) / repeat(4, 1fr);
}
.month-grid {
display: grid;
grid-template: repeat(6, 1fr) / repeat(7, 1fr);
}
Here's a working example: https://codepen.io/loilo/full/ryXLpO/
For simplicity, every month in that pen there has 31 days and starts on a Monday.
I also chose a ridiculously small font size to demonstrate the problem:
Grid items (= day cells) are pretty condensed as there are several hundreds of them on the page. And as soon as the day number labels become too large (feel free to play around with the font size in the pen using the buttons on the upper left) the grid will just grow in size and exceed the page's body size.
Is there any way to prevent this behaviour?
I initially declared my year grid to be 100% in width and height so that's probably the point to start at, but I couldn't find any grid-related CSS properties that would've fitted that need.
Disclaimer: I'm aware that there are pretty easy ways to style that calendar just without using CSS Grid Layout. However, this question is more about the general knowledge on the topic than solving the concrete example.
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?
The previous answer is pretty good, but I also wanted to mention that there is a fixed layout equivalent for grids, you just need to write minmax(0, 1fr) instead of 1fr as your track size.
The existing answers solve most cases. However, I ran into a case where I needed the content of the grid-cell to be overflow: visible. I solved it by absolutely positioning within a wrapper (not ideal, but the best I know), like this:
.month-grid {
display: grid;
grid-template: repeat(6, 1fr) / repeat(7, 1fr);
background: #fff;
grid-gap: 2px;
}
.day-item-wrapper {
position: relative;
}
.day-item {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 10px;
background: rgba(0,0,0,0.1);
}
https://codepen.io/bjnsn/pen/vYYVPZv

Is it possible to use a fixed min and max width for columns in a CSS grid which are repeating and wrappable?

I'd like to set up a CSS layout where a container contains a fixed number of flexible width tiles with the following properties:
Spacing in between tiles is fixed and consistent
They can expand in size between a fixed min and max width, but should all be the same width irrespective of their content. In the example below I'm using 100px min width and 200px max width.
They should wrap onto multiple lines if at their minimum width they don't all fit horizontally in the container.
If the container is much larger they should not expand larger than their maximum fixed width, should remain centered in the container and the space between them should not expand.
Perhaps it's not possible with pure CSS, but it feels like it should be! There's a minimal example below, which I'll detail here:
https://jsfiddle.net/vztskh6f/1/
Option 1: CSS Grid
This seems to be the best candidate, seeing as we always want tile widths to be consistent. In order to get columns to wrap I believe you need to use the repeat() syntax and repeat(auto-fit, ...) seems best for this use case. The obvious solution seems to be to use repeat(auto-fit, minmax(100px, 200px)). However, this does not work tiles always remain at 200px irrespective of the width of the container. In every other way this is behaving as desired:
.gridContainer {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 200px));
padding: 10px;
gap: 10px;
justify-items: center;
justify-content: center;
}
.child {
width: 100%;
height: 30px;
background: #0f0;
text-align: center;
}
It could be possible to enforce the desired spec with Option 1, by using grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)) and then setting a computed max-width on the container and forcing it to center too, but it feels like this should be possible with CSS Grid alone?
Option 2: Flexbox
Wrapping is much simpler to achieve with flexbox and using the flex on a child means we can easily set flexible tiles with min and max widths. However once a child wraps onto a second line, it will obviously expand to its max width and will be inconsistent with other tiles:
.flexContainer {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.child {
height: 30px;
background: #0f0;
text-align: center;
min-width: 100px;
max-width: 200px;
// this seems to create consistent widths better than flex: 1 1 100px;
flex: 1 1 0;
// could use gap if it wasn't for Safari
margin: 0 5px 10px;
}
Screenshots
The first row is the grid layout, the second is the flex layout, you can see these are behaving nicely at full width, not expanding beyond their max widths with consistent spacing between them:
As the container shrinks you can see that the grid layout items are not shrinking with it, but immediately wrap. flex layout behaves nicely:
As the container continues to shrink, the flex starts to wrap in the desired place, but immediately the tile on the next row expands to its max width:
In order to achieve what you're trying to do, you'll need to work on both the container and the child.
On the container, you'll set a min-width to 100px and a max that should be the size of the child:
.gridContainer {
grid-template-columns: repeat(auto-fit, minmax(100px, max-content));
}
And on each child, you'll have a fixed width, but a max-width of 100% so it shrinks if needed:
.child {
width: 200px;
max-width: 100%;
}
Updated fiddle: https://jsfiddle.net/7exd5hom/

Why nested element in CSS grid item is not scrollable? [duplicate]

TL;DR: Is there anything like table-layout: fixed for CSS grids?
I tried to create a year-view calendar with a big 4x3 grid for the months and therein nested 7x6 grids for the days.
The calendar should fill the page, so the year grid container gets a width and height of 100% each.
.year-grid {
width: 100%;
height: 100%;
display: grid;
grid-template: repeat(3, 1fr) / repeat(4, 1fr);
}
.month-grid {
display: grid;
grid-template: repeat(6, 1fr) / repeat(7, 1fr);
}
Here's a working example: https://codepen.io/loilo/full/ryXLpO/
For simplicity, every month in that pen there has 31 days and starts on a Monday.
I also chose a ridiculously small font size to demonstrate the problem:
Grid items (= day cells) are pretty condensed as there are several hundreds of them on the page. And as soon as the day number labels become too large (feel free to play around with the font size in the pen using the buttons on the upper left) the grid will just grow in size and exceed the page's body size.
Is there any way to prevent this behaviour?
I initially declared my year grid to be 100% in width and height so that's probably the point to start at, but I couldn't find any grid-related CSS properties that would've fitted that need.
Disclaimer: I'm aware that there are pretty easy ways to style that calendar just without using CSS Grid Layout. However, this question is more about the general knowledge on the topic than solving the concrete example.
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?
The previous answer is pretty good, but I also wanted to mention that there is a fixed layout equivalent for grids, you just need to write minmax(0, 1fr) instead of 1fr as your track size.
The existing answers solve most cases. However, I ran into a case where I needed the content of the grid-cell to be overflow: visible. I solved it by absolutely positioning within a wrapper (not ideal, but the best I know), like this:
.month-grid {
display: grid;
grid-template: repeat(6, 1fr) / repeat(7, 1fr);
background: #fff;
grid-gap: 2px;
}
.day-item-wrapper {
position: relative;
}
.day-item {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 10px;
background: rgba(0,0,0,0.1);
}
https://codepen.io/bjnsn/pen/vYYVPZv

How to stretch last grid item across full width of screen, when it goes to new row?

I have:
display: grid;
grid-template-columns: repeat(auto-fit, minmax(30rem, 1fr));
gap: 1rem;
When there is not enough space to fit all three containers to fit, one of my containers jump down. Which is fine.
Then the grid has 2 columns and 2 rows. I want the last element to occupy full width of sceen. So, to occupy 2 grid rows instead of one. I can do this manually with media-query, but isn't there a better way to do it?
Not sure if grid is your best option in this scenario.
You might want to use a flex container, setting flex-grow: 1 and min-width on the items.
Example:
.container {
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
}
.item {
min-width: 30rem;
flex-grow: 1;
box-sizing: border-box;
justify-content: space-between;
}
And then using negative margin on the container, plus margin on the items to use as the gap.

How to set equal margin to rows and columns in CSS grid?

I have such container
#container{
display: grid;
grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
}
of such items
.picture_tile{
width:200px;
height: 200px;
position: relative;
background: white;
color: black;
margin: auto;
}
it adjusts nicely horizontally. It nicely adjusts while scaling my monitor, is it possible to apply space between the images to rows as well? I am total beginner to CSS. Is it possible to apply the same space that is changing between the items on vertical gap? When I scale my monitor and the items' horizontal gap is anything between 10-50px. Can the same change apply on vertical gap while changing horizontal size of my window? I hope it's understandable. I only want to have perfect grid with perfect gaps, everything same, but the content would be dynamic and behave like when display: grid is applied
You can use grid-gap: value property on your #container

Resources