Is it possible to make a CSS grid wrap without using media queries?
In my case, I have a non-deterministic number of items that I want placed in a grid and I want that grid to wrap. Using Flexbox, I'm unable to reliably space things nicely. I'd like to avoid a bunch of media queries too.
Here's some sample code:
.grid {
display: grid;
grid-gap: 10px;
grid-auto-flow: column;
grid-template-columns: 186px 186px 186px 186px;
}
.grid > * {
background-color: green;
height: 200px;
}
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
And here's a GIF image:
As a side-note, if anyone can tell me how I could avoid specifying the width of all the items like I am with grid-template-columns that would be great. I'd prefer the children to specify their own width.
Use either auto-fill or auto-fit as the first argument of the repeat() notation.
<auto-repeat> variant of the repeat() notation:
repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
auto-fill
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 its grid container.
https://www.w3.org/TR/css-grid-1/#valdef-repeat-auto-fill
.grid {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, 186px);
}
.grid>* {
background-color: green;
height: 200px;
}
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
The grid will repeat as many tracks as possible without overflowing its container.
In this case, given the example above (see image), only 5 tracks can fit the grid-container without overflowing. There are only 4 items in our grid, so a fifth one is created as an empty track within the remaining space.
The rest of the remaining space, track #6, ends the explicit grid. This means there was not enough space to place another track.
auto-fit
The auto-fit keyword behaves the same as auto-fill, except
that after grid item placement any empty repeated tracks are collapsed.
https://www.w3.org/TR/css-grid-1/#valdef-repeat-auto-fit
.grid {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fit, 186px);
}
.grid>* {
background-color: green;
height: 200px;
}
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
The grid will still repeat as many tracks as possible without overflowing its container, but the empty tracks will be collapsed to 0.
A collapsed track is treated as having a fixed track sizing function of 0px.
Unlike the auto-fill image example, the empty fifth track is collapsed, ending the explicit grid right after the 4th item.
auto-fill vs auto-fit
The difference between the two is noticeable when the minmax() function is used.
Use minmax(186px, 1fr) to range the items from 186px to a fraction of the leftover space in the grid container.
When using auto-fill, the items will grow once there is no space to place empty tracks.
.grid {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));
}
.grid>* {
background-color: green;
height: 200px;
}
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
When using auto-fit, the items will grow to fill the remaining space because all the empty tracks will be collapsed to 0px.
.grid {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(auto-fit, minmax(186px, 1fr));
}
.grid>* {
background-color: green;
height: 200px;
}
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
Playground:
CodePen
Inspecting auto-fill tracks
Inspecting auto-fit tracks
You want either auto-fit or auto-fill inside the repeat() function:
grid-template-columns: repeat(auto-fit, 186px);
The difference between the two becomes apparent if you also use a minmax() to allow for flexible column sizes:
grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));
This allows your columns to flex in size, ranging from 186 pixels to equal-width columns stretching across the full width of the container. auto-fill will create as many columns as will fit in the width. If, say, five columns fit, even though you have only four grid items, there will be a fifth empty column:
Using auto-fit instead will prevent empty columns, stretching yours further if necessary:
You may be looking for auto-fill:
grid-template-columns: repeat(auto-fill, 186px);
Demo: http://codepen.io/alanbuchanan/pen/wJRMox
To use up the available space more efficiently, you could use minmax, and pass in auto as the second argument:
grid-template-columns: repeat(auto-fill, minmax(186px, auto));
Demo: http://codepen.io/alanbuchanan/pen/jBXWLR
If you don't want the empty columns, you could use auto-fit instead of auto-fill.
I had a similar situation. On top of what you did, I wanted to center my columns in the container while not allowing empty columns to for them left or right:
.grid {
display: grid;
grid-gap: 10px;
justify-content: center;
grid-template-columns: repeat(auto-fit, minmax(200px, auto));
}
Here's my attempt. Excuse the fluff, I was feeling extra creative.
My method is a parent div with fixed dimensions. The rest is just fitting the content inside that div accordingly.
This will rescale the images regardless of the aspect ratio. There will be no hard cropping either.
body {
background: #131418;
text-align: center;
margin: 0 auto;
}
.my-image-parent {
display: inline-block;
width: 300px;
height: 300px;
line-height: 300px; /* Should match your div height */
text-align: center;
font-size: 0;
}
/* Start demonstration background fluff */
.bg1 {background: url(https://unsplash.it/801/799);}
.bg2 {background: url(https://unsplash.it/799/800);}
.bg3 {background: url(https://unsplash.it/800/799);}
.bg4 {background: url(https://unsplash.it/801/801);}
.bg5 {background: url(https://unsplash.it/802/800);}
.bg6 {background: url(https://unsplash.it/800/802);}
.bg7 {background: url(https://unsplash.it/802/802);}
.bg8 {background: url(https://unsplash.it/803/800);}
.bg9 {background: url(https://unsplash.it/800/803);}
.bg10 {background: url(https://unsplash.it/803/803);}
.bg11 {background: url(https://unsplash.it/803/799);}
.bg12 {background: url(https://unsplash.it/799/803);}
.bg13 {background: url(https://unsplash.it/806/799);}
.bg14 {background: url(https://unsplash.it/805/799);}
.bg15 {background: url(https://unsplash.it/798/804);}
.bg16 {background: url(https://unsplash.it/804/799);}
.bg17 {background: url(https://unsplash.it/804/804);}
.bg18 {background: url(https://unsplash.it/799/804);}
.bg19 {background: url(https://unsplash.it/798/803);}
.bg20 {background: url(https://unsplash.it/803/797);}
/* end demonstration background fluff */
.my-image {
width: auto;
height: 100%;
vertical-align: middle;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
<div class="my-image-parent">
<div class="my-image bg1"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg2"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg3"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg4"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg5"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg6"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg7"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg8"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg9"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg10"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg11"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg12"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg13"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg14"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg15"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg16"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg17"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg18"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg19"></div>
</div>
<div class="my-image-parent">
<div class="my-image bg20"></div>
</div>
Related
I'm playing around with Css Grid and having problems with fitting overlaying content.
There is a top level container defined as css grid (class="container"), then content grid (class="content") which splits into 3 rows (header, label, rows).
Header is just a header, label contains labels for rows and rows is a content of "table".
Here is what it looks like:
When I resize window I got scroll bar on the right but it's for the whole page. Instead I would like to scroll only rows not the whole page.
Here is the the StackBlitz working example:
https://stackblitz.com/edit/angular-ivy-ayujp5
I guess it's simple but having problems with understanding how height is calculated and where and how overflow properties should be defined.
p {
font-family: Lato;
}
.container {
display: grid;
grid-template-columns: 30px 1fr 30px;
grid-template-rows: 30px 1fr 30px;
grid-template-areas: '. . .' '. content .' '. . .';
}
.content {
grid-area: content;
display: grid;
grid-template-rows: 50px 30px 1fr;
grid-template-areas: 'header' 'label' 'rows';
}
.header {
grid-area: header;
}
.label {
grid-area: label;
display: grid;
grid-template-rows: 1fr;
grid-template-columns: repeat(3, 4fr);
align-items: center;
}
.rows {
grid-area: rows;
height: 100%;
}
.row {
background-color: pink;
margin: 5px 0px;
border-width: 1px;
border-radius: 10px;
padding: 25px;
color: black;
}
<div class="container">
<div class="content">
<div class="header">Header</div>
<div class="label">
<div>Name</div>
<div>From</div>
<div>To</div>
</div>
<div class="rows">
<div class="row">
<div class="label">
<div>1</div>
<div>1999/01/01</div>
<div>1999/12/01</div>
</div>
</div>
<div class="row">
<div class="label">
<div>2</div>
<div>1999/01/01</div>
<div>1999/12/01</div>
</div>
</div>
<div class="row">
<div class="label">
<div>2</div>
<div>1999/01/01</div>
<div>1999/12/01</div>
</div>
</div>
<div class="row">
<div class="label">
<div>3</div>
<div>1999/01/01</div>
<div>1999/12/01</div>
</div>
</div>
<div class="row">
<div class="label">
<div>4</div>
<div>1999/01/01</div>
<div>1999/12/01</div>
</div>
</div>
</div>
I go with height calculation .pin-table { height: calc(100vh - 125px); overflow: auto; } but if anyone has better idea feel free to write.
I have a app which has rows and columns. I can dynamically remove rows. When I remove them then the other items distribute themself equaly over the width of the grid.
Now I want to have something like flex, but with grid. The grid items should have a margin to the next item beside them. Like that. And not distribute themself over the width.
CSS
.column {
padding: 10px;
margin: 10px 0;
display: grid;
grid-auto-flow: column;
.row-item {
text-align: center;
display: grid;
grid-auto-rows: 25px;
grid-row-gap: 10px;
width: 9vw;
}
}
HTML
<div class="column">
<ng-container *ngFor="let jS of journeyStepDisplay">
<div *ngIf="jS.display" class="row-item">
<div class="column-item header">
<p>{{ jS.name }}</p>
</div>
</div>
</ng-container>
</div>
If you have a minimum and/or a max width of the grid items that are to be distributed, you can use a combination of different grid properties to get the desired outcome, like
grid-template-columns: repeat(auto-fit, minmax(100px, 100px));
In the example below, we have a grid where the items will be distributed evenly with a min/max width of 100px. If they can't fit into the row a new row will be inserted.
.container {
height: 200px;
width: 600px;
gap: 5px;
border: 2px solid red;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 100px));
grid-template-rows: auto;
padding: 10px;
}
.box {
border: 2px solid blue;
}
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
You have to declare width for each item.
<div class="column">
<div class="row-item">
<div class="column-item header">
<p>ciao</p>
</div>
</div>
<div class="row-item">
<div class="column-item header">
<p>ciao2</p>
</div>
</div>
<div class="row-item">
<div class="column-item header">
<p>ciao3</p>
</div>
</div>
</div>
.column {
width: 100%;
display: grid;
grid-template-columns: 150px 150px 150px 150px;
grid-template-rows: auto;
}
.row-item {
text-align: center;
}
here a useful guide.
(I didn't use directive from angular, but you can add it)
started using CSS grid instead of boostrap, and im having some issue to get it right.
i want to create a grid layout that have 4fr, and 8fr columns (just like boostrap 8 and 4 columns)
and when the divs inside the grid of 4r gets fill its the divs go to a second row just like flex-wrap:wrap.
BUT Its not work its only push it inline one after another, and ignoring the grid boundaries
.home {
display: grid;
grid-template-columns: 4fr 8fr;
grid-template-rows: 100%;
height: 100%;
}
<div class="home">
<div class="col-8">
</div>
<div class="col-4">
<mat-button-toggle-group class="side-menu-button">
<mat-button-toggle>test </mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
<mat-button-toggle>test</mat-button-toggle>
</mat-button-toggle-group>
</div>
</div>
i even tried changing it to
grid-template-columns: repeat(1, auto-fill, 4fr 8fr);
If you're just wanting to use the grid to have items wrap inside of a div, what you're doing should basically work. Don't forget to tell .col-8 and .col-4 where they belong inside of the grid you've set up, and set the children you want to wrap to inline-block:
* {
box-sizing: border-box;
}
.home {
display: grid;
grid-template-columns: repeat(12, 1fr);
grid-template-rows: 100%;
height: 100%;
width: 100%;
grid-gap: 20px;
}
.col-8 {
grid-area: 1/1/1/9;
}
.col-4 {
grid-area: 1/9/1/13;
}
.bluebox,
.blackbox {
display: inline-block;
width: 50px;
height: 20px;
}
.bluebox {
background-color: blue;
}
.blackbox {
background-color: black;
}
<div class="home">
<div class="col-8">
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
<div class="bluebox"></div>
</div>
<div class="col-4">
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
<div class="blackbox"></div>
</div>
</div>
The reason I set up 12 columns instead of one that's 8fr and one that's 4fr is because I'm unclear about whether you're wanting a 12 column usable system like bootstrap (which is the way I implemented it), or literally only two columns. Either way should function for what you are describing in your question, but 12 separate columns is arguably more extensible later-on.
Here's a pen that contains the above code:
https://codepen.io/grantnoe/pen/MdOQOv
grid-area is what I used to set the location of .home's children. The format is as follows:
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
The only caveat is that you've nested the children you're wanting to wrap inside of secondary element <mat-button-toggle-group>. Consider adjusting the width of that element to 100% to fill the grid's child .col-4.
I am new to CSS grid and tried hard but no luck, I am creating a printable format for A4 paper,and have setup fixed sizes for the columns. The content of the column "UNIT" in the first row (excluding Header row) is spanned/expanded to the next column whenever VALUE entered exceeds the width/border. I want the VALUE (i.e "UnitName12345678") not to cross the border but move to the next line in the same column. Also in minmax(50px , max-content) 50px is applied to only the HEADER row and what I am missing in to apply that to all the rows.
This Container will be having multiple rows generated dynamically.
Present output:
Expected output:
Code Pen : https://codepen.io/thaslim123/pen/gyQwmm
body {
margin: 0px;
}
.printcontainertable {
display: inline-grid;
grid-template-rows: minmax(50px, max-content);
grid-template-columns: 100px 500px 100px 100px 100px 100px;
width: 1150px;
padding: 10px;
}
.printcontainertable div {
border: 1px solid black;
text-align: center;
}
<div class="printcontainertable">
<div> SL.No</div>
<div> Product name</div>
<div> Unit</div>
<div> Qty</div>
<div> Price</div>
<div> total</div>
<div> 1. </div>
<div> Apple </div>
<div>UnitName12345678</div>
<div>10</div>
<div> 100.00 </div>
<div> 1000.00 </div>
<div> 2. </div>
<div> Orange </div>
<div>UnitName</div>
<div>10</div>
<div> 100.00 </div>
<div> 1000.00 </div>
</div>
PS: As I will be having fixed HEADER and FOOTER container on top and bottom of the above container (i.e .printcontainertable), How can I fix a static Height for the same. Kindly Suggest me if any other better way to implement it in GRID.
Alright, I do think there are some other things that can be improved depeniding on exactly what you need (semantics, structure, etc.) the main issue regarding the word that exceeds the border can be fixed by applying word-break: break-word to the item that contains the text.
body {
margin: 0px;
}
.printcontainertable {
display: inline-grid;
grid-template-rows: minmax(50px, max-content);
grid-template-columns: 100px 500px 100px 100px 100px 100px;
width: 1150px;
padding: 10px;
}
.printcontainertable div {
border: 1px solid black;
text-align: center;
}
.unitname {
word-break: break-word;
}
<div class="printcontainertable">
<div> SL.No</div>
<div> Product name</div>
<div> Unit</div>
<div> Qty</div>
<div> Price</div>
<div> total</div>
<div> 1. </div>
<div> Apple </div>
<div class="unitname">UnitName12345678</div>
<div>10</div>
<div> 100.00 </div>
<div> 1000.00 </div>
<div> 2. </div>
<div> Orange </div>
<div>UnitName</div>
<div>10</div>
<div> 100.00 </div>
<div> 1000.00 </div>
</div>
I want the VALUE (i.e "UnitName12345678") not to cross the border but move to the next line in the same column.
Then allow the unbroken line of text to break into multiple lines. Use the overflow-wrap property.
Add this to your code:
.printcontainertable div {
overflow-wrap: break-word;
}
Also in minmax(50px , max-content), 50px is applied to only the HEADER row and what I am missing is to apply that to all the rows.
You're using grid-template-rows. This creates explicit rows, meaning rows that you define.
So when you say this:
grid-template-rows: minmax(50px , max-content);
...you're defining only one row with that rule.
You need to use grid-auto-rows, which applies to implicit rows, which is what you need when rows are generated dynamically.
Make this adjustment to your code:
.printcontainertable {
display: inline-grid;
/* grid-template-rows: minmax(50px , max-content); */
grid-auto-rows: minmax(50px , max-content); /* new */
grid-template-columns: 100px 500px 100px 100px 100px 100px;
width:1150px;
padding:10px;
}
.printcontainertable {
display: inline-grid;
/* grid-template-rows: minmax(50px , max-content); */
grid-auto-rows: minmax(50px, max-content); /* new */
grid-template-columns: 100px 500px 100px 100px 100px 100px;
width: 1150px;
padding: 10px;
}
.printcontainertable div {
overflow-wrap: break-word; /* new */
border: 1px solid black;
text-align: center;
}
body {
margin: 0px;
}
<div class="printcontainertable">
<div> SL.No</div>
<div> Product name</div>
<div> Unit</div>
<div> Qty</div>
<div> Price</div>
<div> total</div>
<div> 1. </div>
<div> Apple </div>
<div>UnitName12345678</div>
<div>10</div>
<div> 100.00 </div>
<div> 1000.00 </div>
<div> 2. </div>
<div> Orange </div>
<div>UnitName</div>
<div>10</div>
<div> 100.00 </div>
<div> 1000.00 </div>
</div>
I have a layout in which multiple items will be aligned in a grid. Let's use the following as an example:
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 20px;
}
.grid-item {
display: block;
width: 100%;
background-color: purple;
color: white;
text-align: center;
padding: 30px 5px;
}
<div class="grid-container">
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
</div>
In the above code, the grid will repeat 3 columns per row and each item will expand to 1/3 of the row width. The problem is that in a responsive situation, the grid will always repeat 3 columns.
If I change the repeat value to auto-fit and adjust the column sizing to use minmax I can control how the page scales down and reduce the col width and count to some sane value. So adjusted code would look something like this:
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px,1fr));
grid-gap: 20px;
}
.grid-item {
display: block;
width: 100%;
background-color: teal;
color: white;
text-align: center;
padding: 30px 5px;
}
<div class="grid-container">
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
</div>
This works well scaling down, but here is where I am having problems - I want to cap the number of cols at 3 when the page scales up. Ideally, I would like to use minmax in the repeat directive like this:
grid-template-columns: repeat( minmax(1, 3), minmax(300px, 1fr) );
but of course this doesn't work. How can I limit repeat to 3 columns while still maintaining my downscale settings with auto-fit?
I don't think you can set a max-limit on the number of columns using auto-fit or auto-fill. By definition, they will create as many tracks as can fit in the container without overflowing:
ยง 7.2.2.2. Repeat-to-fill: auto-fill and auto-fit
repetitions
When auto-fill [or auto-fit] is given as the repetition number ...
then the number of repetitions is the largest possible positive
integer that does not cause the grid to overflow its grid container.
And you can't set the max value of the minmax() function to 30%, because then you run into the same problem you had in your first example:
grid-template-columns: repeat(3, 1fr)
Namely, the column tracks become fixed on all screen sizes, and the layout is not responsive.
I understand that you're looking for a solution that doesn't require media queries. But if you want to use grid layout, I think media queries may be your best bet.
Otherwise, consider flex layout:
jsFiddle demo
.grid-container {
display: flex;
flex-wrap: wrap;
}
.grid-item {
width: 30%;
min-width: 300px;
flex-grow: 1;
background-color: teal;
color: white;
text-align: center;
padding: 30px 5px;
border: 5px solid white;
}
* {
box-sizing: border-box;
}
<div class="grid-container">
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
<div class="grid-item">Item</div>
</div>
If you go the flex route, then read this post, too:
Targeting flex items on the last row
if I understand correctly what you can do is set a media query for larger screens. Lets say you want to show a 3 column grid for screens over 992px you can use something like this
#media only screen and (min-width: 992px){
.grid-container{
grid-template-columns: repeat(3, 1fr);
}
}
Let me know if that helps you! check it here https://codepen.io/anon/pen/Krzbmz
I solved a similar issue by setting max-width to the grid. I had my columns as repeat(auto-fit, 150px). I wanted a max number of columns as x4 with 50px gap. So max-width of grid set to 800px.