Centering in CSS grid with a fixed width column - html

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;
}

Related

Page overflowing with gird repeat auto-fit

I have a grid with an auto-fit. It's working fine, but on smaller (< 350) screens, it's overflowing. How can fixe this? Basically have 350 as long as it's possible and shrink otherwise.
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 1rem;
}
.item {
background-color: crimson;
height: 200px;
border-radius: 2rem;
}
<div class="grid">
<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>
You can nest another property inside minmax(), e.g. min():
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(100%, 350px), 1fr));
gap: 1rem;
}
.item {
background-color: crimson;
height: 200px;
border-radius: 2rem;
}
<div class="grid">
<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>
This should achieve what you're looking for:
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(350px, 100%), 1fr));
gap: 1rem;
}
Your minimum width was not responsive, so I've fixed that by adding a value of 100% inside the minmax using min().

Centre CSS Grid Items Dependent On Dynamic Content Count

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>

CSS Grid inside parent with absolute positioning issue

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>

How to efficiently make the Grid take space based on the content inside of it?

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>

How can I arrange elements inside a wrapper like the example below?

I need to arrange following elements as This sample Image with CSS Flexbox.
.wrapper {
width: 60%;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.element {
width: 200px;
height: 200px;
background: green;
margin-bottom: 20px;
}
<div class="wrapper">
<div class="element large"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element large"></div>
</div>
I have tried few styles but couldn't get successful. Is there any way to fix this with css flex?
In case you change your mind, the Grid solution:
.grid {
width: 60%;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(4, 100px); /* "width" */
grid-template-rows: repeat(4, 100px); /* "height" */
grid-gap: 10px; /* gap between items */
justify-content: center; /* horizontally centered */
}
.item {
background: green;
}
.larger {
grid-column: 1 / span 2; /* starts at the 1st column & spans two */
grid-row: 1 / span 2; /* starts at the 1st row & spans two */
/* can also omit the 1's since it's the first child */
}
.larger2 {
grid-column: 3 / span 2;
grid-row: 3 / span 2;
}
<div class="grid">
<div class="item larger"></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 class="item larger2"></div>
</div>