I am trying to achieve as many columns as it can fit in a row of a grid using auto-fill.
This is how the code works correctly.
.grid-container {
border: solid 1px green;
padding: 3px;
min-width: 400px;
max-width: 900px;
display: flex;
flex-basis: 900px;
flex-direction: column;
height: 100%;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(294px, 1fr));
grid-gap: 12px;
}
.item {
border: solid 1px red;
min-height: 80px;
}
<div class="drawer">
<div class="grid-container">
<div class="grid">
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
</div>
</div>
</div>
But I need the container drawer to have absolute positioning. If I set it to absolute positioning, the grid autofill stops working and the grid creates just one column without trying to fit more columns.
.grid-container {
border: solid 1px green;
padding: 3px;
min-width: 400px;
max-width: 900px;
display: flex;
flex-basis: 900px;
flex-direction: column;
height: 100%;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(294px, 1fr));
grid-gap: 12px;
}
.item {
border: solid 1px red;
min-height: 80px;
}
.drawer {
position: absolute;
left: 0;
top: 0;
bottom: 0;
height: 100%;
}
<div class="drawer">
<div class="grid-container">
<div class="grid">
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
</div>
</div>
</div>
Why is this happening and how to make the grid work correctly?
The .drawer element has no definite width set.
If you add right: 0 or width: <anything> it will get a width and the grid has a horizontal dimension context to work with.
In your example above the width of the .grid is determined by the min-width of the .grid-container element
body {
/* needed fot this presentation on SE */
/* unclear of needed IRE */
position: relative;
}
.drawer {
position: absolute;
left: 0;
top: 0;
right: 0;
max-width: 100%;
}
.grid-container {
border: solid 1px green;
padding: 3px;
min-width: 400px;
max-width: 900px;
display: flex;
flex-basis: 900px;
flex-direction: column;
height: 100%;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(294px, 1fr));
grid-gap: 12px;
}
.item {
border: solid 1px red;
min-height: 80px;
}
<div class="drawer">
<div class="grid-container">
<div class="grid">
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
<div class="item">This is grid item</div>
</div>
</div>
</div>
Related
I have a series of images that are fetched from a database, and when three or more images are added it visually shows the three columns.
When less than three images are present, because I'm using display: grid; it is currently justified to the left of the parent container (in the code example I've just used red boxes to represent the images).
Is there anyway of having it so that when one or two images are present these are justified to the centre of the parent element. I appreciate I could use javascript to detect how many images are present and if it is less than three, add a class and change the wrapper to display: flex, but I wondered if such a layout was possible with CSS only?
Due to the nature of the layout I do need to use CSS Grid when more than three images are present.
Note: I've commented out two of the red boxes in the HTML to show the initial issue when only one red box is present.
Codepen: https://codepen.io/anna_paul/pen/xxXrVJQ
body {
display: flex;
justify-content: center;
margin: 0
width: 100%;
height: 100vh;
}
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-gap: 1rem;
max-width: 1250px;
}
.box {
width: 200px;
height: 200px;
background: red;
}
<div class="wrapper">
<div class="box"></div>
<!-- <div class="box"></div>
<div class="box"></div> -->
</div>
Do it like below:
.wrapper {
display: grid;
grid-auto-flow:column; /* column flow */
justify-content:center; /* center everything */
grid-gap: 1rem;
max-width: 600px;
border:1px solid;
margin:10px auto;
}
/* make sure you only have 3 columns*/
.box:nth-child(3n + 1) {grid-column:1}
.box:nth-child(3n + 2) {grid-column:2}
.box:nth-child(3n + 3) {grid-column:3}
/**/
.box {
width: 100px;
height: 100px;
background: red;
}
<div class="wrapper">
<div class="box"></div>
</div>
<div class="wrapper">
<div class="box"></div>
<div class="box"></div>
</div>
<div class="wrapper">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<div class="wrapper">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<div class="wrapper">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<div class="wrapper">
<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>
Because you are using 1fr for each column, even if a column has no content it is taking 33% of the free space. You need to specify units other than fr(fraction of the available space) unit:
grid-template-columns: auto auto auto;
grid-template-columns: repeat(3, auto);
grid-template-columns: repeat(3, minmax(min-content, max-content));
Use any of the above. There is a small difference between auto and minmax(min-content, max-content).
Following is the demo with 3 containers with 1, 2 and >3 items respectively:
body {
margin: 0;
width: 100%;
height: 100vh;
}
.demo {
display: flex;
justify-content: center;
}
.wrapper {
display: grid;
grid-template-columns: repeat(3, minmax(min-content, max-content));
grid-gap: 1rem;
width: auto;
max-width: 1250px;
}
.box {
width: 200px;
height: 200px;
background: red;
border: 1px solid;
}
<p>Grid with one item</p>
<div class="demo">
<div class="wrapper">
<div class="box">1</div>
</div>
</div>
<hr>
<p>Grid with two items</p>
<div class="demo">
<div class="wrapper">
<div class="box">1</div>
<div class="box">2</div>
</div>
</div>
<hr>
<p>Grid with >3 items</p>
<div class="demo">
<div class="wrapper">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
</div>
</div>
The 1rem grid-gap will remain even if the column has 0 width. So in your setup, grid inside flex, the item in one item grid will be off by 2rem(2grid-gaps) from the center. If this is not a big deal then no worries.
But if you want exact center then you need to make grid-gap:0. And use spacing in side grid items(.box) like margin: 0.5rem; or padding:0.5rem to make artificial grid-gap.
body {
margin: 0;
width: 100%;
height: 100vh;
}
.demo {
display: flex;
justify-content: center;
}
.wrapper {
display: grid;
grid-template-columns: repeat(3, minmax(min-content, max-content));
width: auto;
max-width: 1250px;
}
.box {
width: 200px;
height: 200px;
background: red;
border: 1px solid;
margin: 0.5rem;
}
<p>Grid with one item</p>
<div class="demo">
<div class="wrapper">
<div class="box">1</div>
</div>
</div>
<hr>
<p>Grid with two items</p>
<div class="demo">
<div class="wrapper">
<div class="box">1</div>
<div class="box">2</div>
</div>
</div>
<hr>
<p>Grid with >3 items</p>
<div class="demo">
<div class="wrapper">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
</div>
</div>
using auto instead of fr and using align-content solve your problem.
body {
display: flex;
justify-content: center;
margin: 0
width: 100%;
height: 100vh;
}
.wrapper {
display: grid;
grid-template-columns: auto auto auto;
align-content : start;
/* grid-gap: 1rem; */
max-width: 1250px;
}
.box {
width: 200px;
height: 200px;
background: red;
margin: 1rem ;
}
<div class="wrapper">
<div class="box"></div>
<!-- <div class="box"></div>
<div class="box"></div> -->
</div>
I have a layout that is a sidebar and a grid both wrapped in a flexbox. I'd like to put a div underneath the grid so it can have prev/next buttons, like in this image, but I can't figure out how to do that. The grid resizes itself with the window so the grid can take as many rows as necessary and then the div should go below that, and be as wide as the grid.
This is what I have, but the div is on the right of the grid:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Boardgame Database</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
aside {
background-color: red;
flex: 1;
min-width: 250px;
}
.grid-container {
flex: 4;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.grid-item {
border: 1px solid black;
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
}
#flex-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
</style>
</head>
<body>
<div id="flex-container">
<aside class="sidebar">
</aside>
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
<div class="grid-item">10</div>
<div class="grid-item">11</div>
<div class="grid-item">12</div>
<div class="grid-item">13</div>
<div class="grid-item">14</div>
<div class="grid-item">15</div>
<div class="grid-item">16</div>
<div class="grid-item">17</div>
<div class="grid-item">18</div>
</section>
<div id="page-buttons">
prev
next
</div>
</div>
Checkout the following Code.
#main{
display :flex;
}
#sidebar{
width:70px;
height: 300px;
border: solid black 1px;
}
#grid-area{
width:200px;
height: 300px;
border: solid black 1px;
display: block;
}
#grid{
width:200px;
height: 250px;
border: solid black 1px;
display: block;
}
<div id="main">
<div id="sidebar"></div>
<div id="grid-area">
<div id="grid"></div>
<div id="button">next / prev</div>
</div>
</div>
You should use nested flex containers. Section and bottom div should be wrapped inside another flex container with flex direction to column.
So outer flex will make sidebar & inner flex container to be side by side.
Or just use a normal div container instead of flex.
here is another example only with grid keeping the pre/next button at the bottom of the viewport:
body {
margin: 0;
}
#grid-container {
display: grid;
height: 100vh;
grid-template-columns: minmax(250px, 1fr) 4fr;
grid-template-rows: 1fr auto;
}
aside {
background-color: red;
border: 1px solid;
margin: 0.25em;
grid-row: span 2;
grid-column: 1;
}
section,
#page-buttons {
grid-column: 2;
border: solid 1px;
margin: 0.25em;
}
section {
overflow: auto;
}
#page-buttons {
display: flex;
gap: 1em;
padding: 0.5em;
background: lightgray;
justify-content: center;
}
.grid-item {
border: 1px solid black;
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
}
<div id="grid-container">
<aside class="sidebar">
</aside>
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
<div class="grid-item">10</div>
<div class="grid-item">11</div>
<div class="grid-item">12</div>
<div class="grid-item">13</div>
<div class="grid-item">14</div>
<div class="grid-item">15</div>
<div class="grid-item">16</div>
<div class="grid-item">17</div>
<div class="grid-item">18</div>
</section>
<div id="page-buttons">
prev
next
</div>
</div>
How can I force .item2 to be placed in-line with .item1 by only changing CSS of .item2? (I know that you would usually just change .container to flex-direction: row)
.container {
display: flex;
flex-direction: column;
background: blue;
padding: 1rem;
}
.item1 {
background: yellow;
}
.item2 {
background: red;
}
<div class="container">
<div class="item1">Item 1</div>
<div class="item2">Item 2</div>
</div>
.container {
display: grid;
grid-template-columns: repeat(2, auto);
background: blue;
padding: 1rem;
gap: 0.25em;
}
/* here the class to use for a full row */
.itemNext {
grid-column: 1 / span 2;
background: hotpink;
}
.item1 {
background: yellow;
}
.item2 {
background: red;
}
<div class="container">
<div class="item1">Item 1</div>
<div class="item2">Item 2</div>
<div class="itemNext">next Item </div>
<div class="itemNext">next Item </div>
<div class="item1 itemNext">next Item </div>
<div class="item2 itemNext">next Item </div>
<div class="item1">Item 1</div>
<div class="item2">Item 2</div>
<div class="itemNext">next Item </div>
</div>
Im trying to make a simple CSS centered grid layout.
I know that when I use justify-items: center, the items inside a grid container are supposed to align horizontally, but when I specify a column width in pixels like this grid-template-columns: repeat(3, 100px) the whole grid return to normal. So is there any way to make the grid items centered but in same time specify the column width in pixels?
Here are my example:
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
.container {
background-color: #aa96da;
display: grid;
justify-items: center;
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}
Change the justify-items to justify-content and it should work.
.container {
background-color: #aa96da;
display: grid;
/* justify-items: center; */
justify-content: center;
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Short answer: You want justify-content not justify-items
.container {
background-color: #aa96da;
display: grid;
justify-content: center; /* -items to -content */
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Long answer:
There's a difference between the grid item and the space it lives in.
When you define a grid, you're only defining rows/columns of the grid called tracks, Not actually defining where each element goes etc.
The DOM elements only follow the flow of the grid and are placed accordingly, which we can alter using properties like grid-column grid-row
You can look at it like this:
As you can see there's The Grid container, The Grid, The Columns, The Rows and then The Grid items.
The Grid items lives in the intersection between the two called The Grid Area (this what makes css grid better than flexbox in some ways)
And justify-items aligns the grid items within that area.
So grid-template-columns: repeat(3, 1fr); This means 3 columns their width is the width of the grid split evenly between them.
Demo
Don't look at the code just the preview
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
[grid] {
height: 300px;
display: flex;
border: 2px solid;
padding: 10px;
flex-wrap: wrap;
}
[column] {
flex: 1 0 calc(100% / 3);
border: 2px solid;
display: flex;
flex-direction:column;
align-items:center;
}
[column]>div {
width: 100px;
flex:1;
background-color: green;
}
<div grid>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
</div>
As you can see the grid columns are wider than the grid items 100px which means there space to center stuff, So justify-items: center; will center them inside.
That's why it looks like the grid is centered, But it's actually not reasons why changing to grid-template-columns: repeat(3, 100px); breaks it.
In the case of grid-template-columns: repeat(3, 100px);
Demo
Don't look at the code just the preview
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
[ctr] {
border: 2px solid;
padding: 10px;
}
[grid] {
height: 300px;
width: 340px;
display: flex;
padding: 10px;
flex-wrap: wrap;
}
[column] {
flex: 0 0 100px;
border: 2px solid;
display: flex;
flex-direction: column;
align-items: center;
}
[column]>div {
width: 100px;
flex: 1;
background-color: green;
}
<div ctr>
<div grid>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
<div column>
<div>Grid Item</div>
</div>
</div>
</div>
As you can see the columns width equal the grid item's so they all fit snugly within the columns and the grid is still empty.
You can try adding the flex property on top of those grid elements and then center it with justify-content:center;
index.html:
<div class="centering_items">
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
style.css
.centering_items {
display: flex;
justify-content: center;
}
.container {
background-color: #aa96da;
display: grid;
grid-gap: 20px;
grid-template-rows: repeat(3, 1fr);
/*Only if I change this 100px to '1fr' the justify-items will work */
grid-template-columns: repeat(3, 100px);
}
.item {
width: 100px;
height: 100px;
background-color: green;
}
That's a prime example of something that CSS Grid will do better than flexbox. Something like this:
#container{
display: flex;
width:100%;
height:100%;
}
#wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
outline: 1px solid red;
width: 72%;
height: 100%;
padding: 24px 0px;
box-sizing: border-box;
}
.item {
background-color: yellow;
height: 30px;
margin: 15px;
max-width:110px;
border-radius: 8px;
cursor: pointer;
}
Here the cards looks good as the number of cards are more
<div id ="container">
<div id="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
<hr/>
we have so much white space between cards, how can we get rid of the space as the cards can be dynamic like 2 or 1. and a max of 3 per container
<div id ="container">
<div id="wrapper">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
How can we have the space between grids and make them left aligned so that it , fits correctly as the top cards, dynamically adjust using Css Grids or is there any efficient way of achieving this.
Note - One thing that blocks me here is we cannot have a fixed width and then have the grid at 3 columns as we donot want to have empty spaces when the container is resized
You could remove the minmax(100px, 1fr) and just use a fixed column width. Here is an example:
#container {
display: flex;
width: 100%;
height: 100%;
}
#wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, 100px);
outline: 1px solid red;
width: 72%;
height: 100%;
padding: 24px 0px;
box-sizing: border-box;
}
.item {
background-color: yellow;
height: 30px;
margin: 15px;
max-width: 110px;
border-radius: 8px;
cursor: pointer;
}
Here the cards looks good as the number of cards are more
<div id="container">
<div id="wrapper">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
<hr/> we have so much white space between cards, how can we get rid of the space as the cards can be dynamic like 2 or 1. and a max of 3 per container
<div id="container">
<div id="wrapper">
<div class="item"></div>
<div class="item"></div>
</div>
</div>
You can use this code
body {
margin: 15px;
}
.three-col-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
outline: 1px solid red;
width: 72%;
height: 100%;
padding: 24px 0px;
box-sizing: border-box;
}
.l-wrap {
margin-right: auto;
margin-left: auto;
display: flex;
}
.grid-item {
margin-top: 0px;
padding-left: 12px;
padding-right: 12px;
float: left;
}
.grid-inner {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
background-color: yellow;
height: 30px;
margin: 15px;
max-width: 200px;
border-radius: 8px;
}
Here the cards looks good as the number of cards are more
<div class="l-wrap">
<div class="three-col-grid">
<div class="grid-item">
<div class="grid-inner">Grid item</div>
</div>
<div class="grid-item">
<div class="grid-inner">Grid item</div>
</div>
<div class="grid-item">
<div class="grid-inner">Grid item</div>
</div>
<div class="grid-item">
<div class="grid-inner">Grid item</div>
</div>
<div class="grid-item">
<div class="grid-inner">Grid item</div>
</div>
</div>
</div>
<br><br>we have so much white space between cards, how can we get rid of the space as the cards can be dynamic like 2 or 1. and a max of 3 per container
<div class="l-wrap">
<div class="three-col-grid">
<div class="grid-item">
<div class="grid-inner">Grid item</div>
</div>
<div class="grid-item">
<div class="grid-inner">Grid item</div>
</div>
</div>
</div>