This is something that I've been struggling with for a while, but I can't seem to find a way to do it.
If you have an odd number of items in grid and you want 2 items per row (1fr 1fr), you end up with a single item in the last row that is left-centered.
I just want to make it centered so it looks nicer.
Here's a picture too.
You can try something like this jsfiddle:
/* visibility properties */
body {
width: 60%;
margin: 5% auto;
}
div {
margin: 3%;
width: 100px;
height: 100px;
background-color: black;
justify-self: center;
}
div:nth-of-type(2n) {
background-color: red;
}
/* actual code: */
section {
display: grid;
grid-template-columns: 1fr 1fr;
}
#last-div {
grid-column: 1 / span 2;
}
<section>
<div>
</div>
<div>
</div>
<div>
</div>
<div>
</div>
<div id="last-div">
</div>
</section>
Get more info on CSS Grid: complete-guide-grid
You could try something like this since I faced a similar issue in one of my earlier projects.
grid-template-columns : repeat(auto-fit, minmax(<minSize>, 1fr));
Set minSize to whatever minimum width you want an element to occupy.
Related
I have a grid that's two columns side by side. However, there's an odd number of elements, so I would like to offset the right column so it's centered vertically against the left column.
What would be the best way to do that using grid?
Here's an example how i want the layout to look:
Here's an example: https://codepen.io/patricktm/pen/JjMzQWj
body {
max-width: 1000px;
margin: auto;
}
.grid-item {
background-color: #ccc;
border: 1px solid;
height: 200px;
}
.grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1em;
}
<body>
<div class='grid'>
<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>
</body>
This layout isn't really feasible with Grid because there are fix row tracks that prevent the free flow of items across the column.
You're basically asking the top item in the second column to somehow space itself down in the first row track and cross into the second track, pushing down the other items along the way.
Grid doesn't work this way. The matter is discussed in detail in this post:
Aligning grid items across the entire row/column (like flex items can)
One simple way to make this layout work uses flexbox, which has no column or row tracks crossing through the flex lines. (You'll have to tweak it though, as my simple example will only work on taller screens. On shorter screens additional columns will be generated.)
.grid {
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: center; /* key */
height: 100vh;
gap: 1em;
}
.grid-item {
background-color: #ccc;
border: 1px solid;
height: 21%; /* prevents a 5th item in the column */
}
body {
max-width: 1000px;
margin: auto;
}
<div class='grid'>
<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>
I'm trying to take a single image and centre it using CSS grid, both as a way to teach myself grid and because my page calls for a single, centred image. The image is centring left-to-right but not top-to-bottom. It sits right at the top. I made the image smaller to make viewing it for test purposes easier. The size of my image is less important than its placement. What am I doing wrong?
Also, I want this in a 3x3 grid, not some other number value.
.wrapper {
display: grid;
display: flex;
justify-content: center;
}
.ConstructGrid {
justify-items: center;
grid-template-rows: repeat(3, 1fr);
grid-template-columns: repeat(3, 1fr);
grid-gap: 1px;
grid-template-areas: ". . ." ". picture ." ". . .";
}
<div class="wrapper">
<div class="ConstructGrid">
<img class="picture" src="http://www.cafenocturne.com/images/Under_Construction.png" border="0" width="400">
</div>
</div>
It's easier than you think.
the container should be the grid, within you can set the child in its area/cell.
an height or min-height is also required even if 1fr would manage some height
body {
margin:0;
}
.wrapper {/* i draw the grid , i'm the boss !*/
height: 100vh;/* let me lay from top to bottom. I'm the boss, i want it whole */
display: grid;
grid-template-rows: repeat(3, 1fr);
grid-template-columns: repeat(3, 1fr);
grid-gap: 1px;
grid-template-areas: ". . ." ". picture ." ". . .";
}
.ConstructGrid {
grid-area: picture;/* tell me where to be, i'm the prisoner */
margin:auto;/* let me be in the center of my area/cell :) */
}
<div class="wrapper">
<div class="ConstructGrid">
<img class="picture" src="http://www.cafenocturne.com/images/Under_Construction.png" border="0" width="400">
</div>
</div>
You didn't use the grid. Because you didn't set display:grid for .ConstructGrid. You can use only flexbox to center the image. Also you should set height: 100% to center it vertically.
html,
body,
.wrapper,
.ConstructGrid {
height: 100%;
}
.ConstructGrid {
display: flex; /* this can be display: grid also */
justify-content: center;
align-items: center;
}
<div class="wrapper">
<div class="ConstructGrid">
<img class="picture" src="http://www.cafenocturne.com/images/Under_Construction.png" border="0" width="400">
</div>
</div>
You should't have both display grid and display flex at the same block of code, otherwise, it will overwritten by the other.
In your code you have display:flex just below of display grid.
Display grid will apply when you remove display flex within .wrapper.
I would solve it like that to reserve the centered Area for the image. I use .picture-container as the wrap-element for the Image and use responsive widths and heights to get it centered right. Flex is only used inside the Wrap-Element for the Image so it doesnt interfere with the Css-Grid:
body{
height: 100vh;
width: 100vw;
padding: 0;
margin: 0;
}
.wrapper {
height: 100%;
width: 100%;
display: grid;
justify-items: center;
grid-template-rows: auto;
grid-template-columns: 25% 25% 25% 25%;
grid-template-areas:
". . . ."
" . image image ."
". . . .";
}
.picture-container{
grid-area: image;
display: flex;
align-items: center;
justify-content: center;
}
<div class="wrapper">
<div class="picture-container">
<img class="picture" src="http://www.cafenocturne.com/images/Under_Construction.png" border="0">
</div>
</div>
I also always prefer to set a height and width for your whole Area in cases like this, thats why i added them to the body. That makes it way easier to position Elements.
I'm trying to position images the way shown in the picture using CSS Grid and I can't find a right solution.
Right now I'm simply changing the grid flow to column, but the grid elements don't jump to another row when they meet the end of the container - they resize it and stay in the same, first row.
I tried to use grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)) - it solves this jump to another line issue, but it gives all the elements a fixed width whereas some images are not that wide. It creates empty holes between images which I'd like to avoid.
Any ideas on how to accomplish it?
wrong solution 1
Code from the image above:
container {
display: grid;
grid-gap: 1rem;
grid-auto-flow: column;
}
photo { // all container's elements have this class
height: 10rem;
width: auto;
}
wrong solution 2
Code from the image above:
container {
display: grid;
grid-gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
photo {
height: 10rem;
max-width: 100%;
}
You see, this is tusk for flex, not for grid. Using grid means columns with same width on each row. No need here at all.
html {
font-size: 10px;
}
.conteiner {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.photo {
height: 10rem;
margin: 0 1rem 1rem 0;
}
.photo img {
width: auto;
height: 100%;
}
<div class="conteiner">
<div class="photo"><img src="https://via.placeholder.com/500x200"></div>
<div class="photo"><img src="https://via.placeholder.com/300x200"></div>
<div class="photo"><img src="https://via.placeholder.com/200x200"></div>
<div class="photo"><img src="https://via.placeholder.com/400x200"></div>
<div class="photo"><img src="https://via.placeholder.com/500x200"></div>
<div class="photo"><img src="https://via.placeholder.com/300x200"></div>
<div class="photo"><img src="https://via.placeholder.com/200x200"></div>
</div>
Although I'm using Justified gallery jQuery plugin, if I wand all images in each row to fill all the width.
This is easiest to explain with an example:
.grid {
display: grid;
grid-gap: 5px 10px;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
}
.grid>div {
background-color: yellow;
white-space: nowrap;
}
<div class="grid">
<div>foo</div>
<div>foo bar</div>
<div>eg ergerg</div>
<div>fo eagro</div>
<div>4ergearg ergearg er</div>
<div>earg erg</div>
<div>bverbr</div>
<div> eargerg </div>
</div>
I want to size all the columns such that they're the same width as the widest column, in this case the one that says "4ergearg ergearg er".
I don't know its width, thus I don't know what to replace that 80px with. min-content, max-content, and auto don't seem to work.
In other words, i want to stretch the columns to prevent the content from overflowing:
Why do I have an overflow on the X axis in the following snippet?
The overflow is generated once I apply grid-gap: 10px on my .body grid container.
div:not(.header):not(.body):not(.row) {
border: 1px solid grey;
}
.header {
margin-top: 20px;
display: grid;
grid-gap: 10px;
grid-template-areas: "header-left header-right-up" "header-left header-right-down";
grid-template-rows: 40px 40px;
grid-template-columns: minmax(50px, 200px) auto;
}
.header-left {
grid-area: header-left;
}
.header-right-up {
grid-area: header-right-up;
}
.header-right-down {
grid-area: header-right-down;
}
.body {
margin-top: 20px;
display: grid;
grid-template-columns: 25% 50% 25%;
grid-auto-rows: 80px;
grid-gap: 10px;
}
.row-left {
}
.row-center {
}
.row-right {
}
<div class="header">
<div class="header-left">image</div>
<div class="header-right-up">content</div>
<div class="header-right-down">long content</div>
</div>
<div class="body">
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
</div>
</div>
https://codepen.io/anon/pen/WdJExz?editors=1100
Short Answer
Because the width of the columns plus the width of the gaps is greater than 100%.
Explanation
You have a 3-column grid container (.body):
grid-template-columns: 25% 50% 25%
The total width of those columns is 100%.
You're then adding gutters between the columns (and rows):
grid-gap: 10px
which is shorthand for:
grid-column-gap: 10px;
grid-row-gap: 10px;
So this becomes the width calculation:
25% + 50% + 25% + 10px + 10px
Hence,
100% + 20px > 100%, which results in an overflow condition
Note that the grid-*-gap properties apply only between grid items – never between items and the container. That's why we calculate two grid gaps, not four.
As a solution, instead of percentage units, try using fr units, which apply only to free space. This means that fr lengths are calculated after any grid-gap lengths are applied.
grid-template-columns: 1fr 2fr 1fr
div:not(.header):not(.body):not(.row) {
border: 1px solid grey;
}
.header {
margin-top: 20px;
display: grid;
grid-gap: 10px;
grid-template-areas: "header-left header-right-up" "header-left header-right-down";
grid-template-rows: 40px 40px;
grid-template-columns: minmax(50px, 200px) auto;
}
.header-left {
grid-area: header-left;
}
.header-right-up {
grid-area: header-right-up;
}
.header-right-down {
grid-area: header-right-down;
}
.body {
margin-top: 20px;
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* ADJUSTMENT */
grid-auto-rows: 80px;
grid-gap: 10px;
}
.row-left {}
.row-center {}
.row-right {}
<div class="header">
<div class="header-left">image</div>
<div class="header-right-up">content</div>
<div class="header-right-down">long content</div>
</div>
<div class="body">
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
<div class="row-left"></div>
<div class="row-center"></div>
<div class="row-right"></div>
</div>
revised codepen demo
More details here: The difference between percentage and fr units
If you want to use percentages or some other unit, there is one more solution. The use of the minmax() function will allow the columns to shrink to fit the parent container and not cause overflow.
The solution would look like this:
grid-template-columns: minmax(auto, 25%) minmax(auto, 50%) minmax(auto, 25%);
gap: 10px;
More on the minmax() function here.
If you have a fixed number of grid columns that should be the same width and use grid-gap, there's a way to do it:
display: grid;
grid-template-columns: repeat(4, calc(25% - 0.75em));
grid-gap: 1em;
In this case, each row would have 4 grid columns, and the total space occupied by grid-gap would be 3em. In order to distribute the overflowing space evenly, divide the space by the number of grid columns.
3em / 4 = 0.75em
This makes all the grid columns have the same width.
Codepen demo
Late reply but 100% worth it.
Summary from many resources.
Usage with %
Grid columns calculated with % are not taking into accounts gutters (aka gaps). Therefore you need to add the pixels of the added gaps to the calculation. so totalGridWidth = SUM(...%) + gutters = ~100% + gutters
Usage with fr
The previous issue does not happen (exception on number 3.) as it includes to calculate the free space as well with the gaps. so calculation is as follow: (free space - gutters) / 12 = 1fr therefore here you could get ratios as fractions instead of portions as percentages.
Or in other words with the Least Common Divisor (1fr = 25%):
grid-template-columns: 1fr 2fr 1fr;
Usage with minmax(0,Xfr)
By default the browser layout engine uses to calculate Xfr this formula minmax(auto,Xfr) which relies on the minimum size of your items, and when any of those items or inner elements are expected to grow in size indefinitely with things like width:100% the auto parameter will make still case 2. to run sometimes with overflown grids. To prevent this, we need to force the browser to use a method that can shrink the elements until its real minimum, which is 0px to do this you need to use minmax(0,Xfr) with X as the desired fraction.
Or in other words, for your previous case:
grid-template-columns: minmax(0,1fr) minmax(0,2fr) minmax(0,1fr);
I know this might look too verbose, but given your such edge case we cannot use repeat() here, and in any case, this will be a bulletproof for your overflowing issues.
You can read more in this article I have found:
https://css-tricks.com/preventing-a-grid-blowout/
I stumbled into this problem too, and what it worked for me was to replace grid-template-column: 50% 50%; with grid-template-column: auto 50%;.