Is there a way to make display grid flexible? - html

I have a group of items that I want to behave like display: flex but in a display: grid layout. What I mean by this is that they are in a grid but the sizes of each grid box are flexible to allow more space for larger titles.
I tried to get the display: grid elements to be more flexible with the css selector grid-auto-columns
<div id="grid">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
</div>
#grid {
height: 100px;
display: grid;
grid-template-areas: "a a";
gap: 10px;
grid-auto-columns: 200px;
}
But I would prefer teat the sections remain rigid in size once they are set instead of being truly flexible

Related

dynamic grid, taking size from child element

I want to create an dynamic grid class. For my React application.
I want the grid columns 20% bigger then the item thats inside.
I have this solution below. My Problem is, that i have a hover effect on the items. And the hover effect adds a margin to the item. That forces the grid to resize. Is there any solution to make the grid 20% bigger then its elements but at the same time ignoring margin?
.grid-dynamic {
display: grid;
grid-template-columns: repeat(auto-fill, 20%);
grid-auto-rows: 120%;
place-items: center;
}
<div classname="grid-dynamic">
<div classname="item"></div>
<div classname="item"></div>
<div classname="item"></div>
<div classname="item"></div>
...
</div>

css grid max-width when number of items doesnt fill the page [duplicate]

I'm working with CSS grids to achieve a card grid layout.
But I don't quite know how to tweak the minmax() statement to handle use cases where there aren't enough items to fill a row but still need them to look like cards!
If I replace the max 1fr value with a static 100px or I use a fractional 0.25fr it upsets the scaling at smaller media sizes.
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-column-gap: 17px;
grid-row-gap: 25.5px;
padding-bottom: 25.5px;
}
.card {
background-color: #000;
height: 100px;
}
<div class="wrapper">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
And then if there are only a couple items
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-column-gap: 17px;
grid-row-gap: 25.5px;
padding-bottom: 25.5px;
}
.card {
background-color: #000;
height: 100px;
}
<div class="wrapper">
<div class="card"></div>
<div class="card"></div>
</div>
The key is to use auto-fill instead of auto-fit.
When the repeat() function is set to auto-fit or auto-fill, the grid container creates as many grid tracks (columns/rows) as possible without overflowing the container.
Note that as the grid container is being rendered, the presence of grid items is irrelevant. The container just lays out the columns and rows as instructed, creating grid cells. It doesn't care if the cells are occupied or unoccupied.
With auto-fit, when there are not enough grid items to fill the number of tracks created, those empty tracks are collapsed.
Taking your code as an example, when there aren't enough grid items to fill all the columns in the row, those empty columns are collapsed. The space that was used by the empty columns becomes free space, which is then evenly distributed among existing items. By absorbing the free space, the items grow to fill the entire row.
With auto-fill, everything is the same as auto-fit, except empty tracks are not collapsed. They are preserved. Basically, the grid layout remains fixed, with or without items.
That's the only difference between auto-fill and auto-fit.
Here's an illustration of three grid items with auto-fill:
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
Here's an illustration of three grid items with auto-fit:
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
spec reference: https://www.w3.org/TR/css3-grid-layout/#auto-repeat
In Short,
Auto-fit: Fit entire length of container.
Auto-fill: Doesn't fit entire length of the contaier.
When using minmax() function, the auto-fit keyword will expand the grid items to fill the available space. While auto-fill will keep the available space reserved without altering the grid items width.

Why is auto-fill property of CSS Grid not working in column direction

I am practicing auto-fill property with rows, however, it is not doing what I desire. I want to create rows with height minmax(140px, 200px), but instead get one row with 200px height and the rest are 18px. Why is it happening?
body,
html {
height: 100%;
margin: 0;
}
.wrapper {
display: grid;
grid-template-rows: repeat(auto-fill, minmax(140px, 200px));
}
.wrapper>div:nth-child(odd) {
background-color: red;
}
<div class="wrapper">
<div class="one"> 1 </div>
<div class="one"> 1 </div>
<div class="one"> 1 </div>
<div class="one"> 1 </div>
<div class="one"> 1 </div>
</div>
To wrap grid in vertical direction you have to do a bit more:
specify a height for the grid container so that the grid items know when to wrap,
also specify grid-auto-flow: column (overriding default grid-auto-flow: row)
See demo below (have set height: 100% for illustration):
body,
html {
height: 100%;
margin: 0;
}
.wrapper {
display: grid;
grid-template-rows: repeat(auto-fill, minmax(140px, 200px));
grid-auto-flow: column; /* added */
height: 100%; /* adjust this*/
}
.wrapper>div:nth-child(odd) {
background-color: red;
}
<div class="wrapper">
<div class="one"> 1 </div>
<div class="one"> 2 </div>
<div class="one"> 3 </div>
<div class="one"> 4 </div>
<div class="one"> 5 </div>
</div>
Why specify a height?
Because auto-fill or auto-fit requires a definite dimension in that axis:
7.2.3.2. Repeat-to-fill: auto-fill and auto-fit repetitions
When auto-fill is given as the repetition number, if the grid
container has a definite size or max size in the relevant axis, then
the number of repetitions is the largest possible positive integer
that does not cause the grid to overflow the content box of its grid
container (treating each track as its max track sizing function if
that is definite or as its minimum track sizing function otherwise,
and taking gap into account); if any number of repetitions would
overflow, then 1 repetition. Otherwise, if the grid container has a
definite min size in the relevant axis, the number of repetitions is
the smallest possible positive integer that fulfills that minimum
requirement. Otherwise, the specified track list repeats only once.
Auto-fill in row direction is simpler
Note that here, you don't need to specify a width as display: grid is a block element and block elements have the width of the viewport. You can just use grid-template-columns: repeat(auto-fill, minmax(140px, 200px)) here:
body,
html {
height: 100%;
margin: 0;
}
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 200px));
/*grid-auto-flow: row; --> default (so not needed) */
}
.wrapper>div:nth-child(odd) {
background-color: red;
}
<div class="wrapper">
<div class="one"> 1 </div>
<div class="one"> 2 </div>
<div class="one"> 3 </div>
<div class="one"> 4 </div>
<div class="one"> 5 </div>
</div>
Why grid-auto-flow: column?
See the relevant excerpts from its definition - this property controls how grid items flow in a grid container if they are not explicitly placed:
grid-auto-flow
The grid-auto-flow CSS property controls how the auto-placement
algorithm works, specifying exactly how auto-placed items get flowed
into the grid.
The default value of grid-auto-flow is row which is why you need to override it to column:
row
The auto-placement algorithm places items by filling each row in turn,
adding new rows as necessary. If neither row nor column is provided,
row is assumed.

How to keep same image heights in fluid CSS grids?

I'm quite new to css grids. I need to code a 2 columns component, with fluid equal height images inside. I could do it with flexbox, but this time I need a css grid, and it must be responsive.
That said, this component has 2 images, 1 per column. The original img files have equal heights (340x300, 708x300). I need to show them about 30% and 70% width, minus gap. I tried to use both 'auto' and fr units, also combined, but no luck.
On the last/large breakpoint, it's all fine:
The problem comes when on smaller breakpoints: I can't keep the 2 images the same exact height (make them scale with same height):
Here's some code, one of the versions. But any variation of this code (different unit combinations) give some kind of problems, and none of them makes me having equal height images:
.images-block-box{
display: grid;
grid-gap: 16px;
grid-template-columns: auto auto;
//grid-template-columns: 1fr auto;
//grid-template-columns: 1fr 2fr;
//grid-template-columns: 33.333% 66.666%;
}
Ah, and obviously, the images are fluid (max-width:100%; height: auto).
How to solve?
The original img files have equal heights (340x300, 708x300).
You can exploit the fact that fractional units work in proportions of the items. So use grid-template-columns: 340fr 708fr if the images file are not going to change. See demo below:
.images-block-box{
display: grid;
grid-gap: 16px;
grid-template-columns: 340fr 708fr;
}
img {
max-width: 100%;
height: auto;
display: block;
}
<div class="images-block-box">
<img src="https://via.placeholder.com/340x300"/>
<img src="https://via.placeholder.com/708x300"/>
</div>
This is my answer. The trick is using img{object-fit: cover;}
.wrap{
width:100vw;
display:grid;
grid-template-columns:3fr 7fr;
grid-gap:1em;
}
.a img{width:100%;height:100%;object-fit: cover;}
<div class="wrap">
<div class="a">
<img src="http://via.placeholder.com/340x300" />
</div>
<div class="a">
<img src="http://via.placeholder.com/708x300" />
</div>
</div>

CSS grid where one column shrinks to fit content, the other fills the remaning space

I need to create a horizontal layout where one block takes all available space and the other ones shrink to fit their content.
For example:
<div class="grid">
<div class="expand">Long text label</div>
<div class="shrink">Button</div>
</div>
A more complex example with two rows (an actual grid):
<div class="grid">
<div class="row">
<div class="shrink">...</div>
<div class="expand">...</div>
<div class="shrink">...</div>
<div class="shrink">...</div>
</div>
<div class="row">
<div class="shrink">...</div>
<div class="expand">...</div>
<div class="shrink">...</div>
<div class="shrink">...</div>
</div>
</div>
My requirements:
The large block should fill all available space even if short
The small blocks should fit their content
The large block (usually a text label) may be a single word larger that the available space, so it should be truncated in this case
The large block should not wrap if multi-word
The small blocks should not wrap (though in the case of multiple buttons or icons, this can be solved by making one block per component)
Support multiple rows (i.e. columns should be aligned)
I am targeting Android and iOS smartphones.
I have tried to adapt the code from this answer but I could not make it work for multiple rows. Also, the source code must be out of order, which is confusing (though not blocking for my use case). Here's a jsfiddle: http://jsfiddle.net/k3W8L/
You need to use grid-template-column and set the size of column you want to shrink-to-fit as auto, and specify the size of at least one other column using the fr unit.
Example:
To recreate the sidebar-content layout, where the sidebar is collapsible,
-------------------------------
| Sidebar | Content |
-------------------------------
you can create the grid as:
.grid {
display: grid;
...
grid-template-columns: auto minmax(0, 1fr); // see note below
grid-template-areas: "sidebar content";
}
.sidebar {
grid-area: sidebar;
}
.content {
grid-area: content;
}
See the codepen here for a demo & code: https://codepen.io/khs/pen/vegPBL
You can click on the navbar to see auto-sizing in action.
Note: One thing I've learnt since writing this answer is that in most cases, and especially in a fixed-height/fixed-width layout, you should use minmax(0, 1fr) instead of 1fr. The reason is that 1fr is actually a shorthand for minmax(auto, 1fr). This breaks when used for fixed layouts with longer content. See this question for more details: Why does minmax(0, 1fr) work for long elements while 1fr doesn't?
Hence I've updated my answer to reflect the fact. The minmax might be a little verbose, but it's almost always what you want for this kind of layout.
Context: I bumped into this question recently while learning to use grid in my app. With some help from ilyaigpetrov's answer, I was able to get a shrink-to-fit column sizing to work. Their answer doesn't give much explanation though, so I thought I'd add this:
I found the answer to my own question while trying to create a concise example.
It makes use of table layout:
.grid {
display: table;
table-layout: auto;
width: 100%;
}
.row {
display: table-row;
}
.expand {
display: table-cell;
width: 100%;
max-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.shrink {
display: table-cell;
white-space: nowrap;
}
The width: 100% in .expand is what makes the block fill all available space, thus fulfilling the first two requirements.
Note that the width in .grid simply sets the width of the entire grid, you can use any value here.
For some reason, putting max-width: 0 in .expand prevents the block to grow more than the available space, a smallish value like 100px will also do. I discovered this by chance and I don't know why it works.
Here's the jsfiddle: http://jsfiddle.net/fr253/
This answer helped me getting started.
I don't know whether my code is valid, but it gets the job done: either with grid or with flex.
.container {
display: grid;
grid-template-columns: 1fr auto auto;
}
.one {
background-color: pink;
}
.two {
background-color: yellow;
}
.three {
background-color: lightgreen;
}
/* Now the same but with flex. */
.whole-row {
grid-column: 1 / -1;
}
.flexy {
display: flex;
border: 1px solid red;
}
.flexy > .one {
flex-grow: 1;
}
.flexy > .two,
.flexy > .three {
/* flex-grow: 0; <- This value is a default. */
}
<div class="container">
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
<div class="whole-row flexy">
<div class="one">one</div>
<div class="two">two</div>
<div class="three">three</div>
</div>
</div>