CSS Grid gap not the same size for column and row - html

I have the following elements:
<body>
<div class="parent">
<div class="grid">
<!--...-->
</div>
</div>
</body>
.parent {
margin: 30px 30px 0 30px;
display: block;
}
.grid {
display: grid;
grid-template-rows: 55% 45%;
grid-template-columns: 20% 48% 30%;
gap: 1%;
}
As you can see, the size of the cells are based on the parent element size (percentual size), and so are the gap size.
The problem is that while the column gap size is just the way I want, the row gap is very thin.
I understand that this is caused because the gap is equal to 1% of the heigth of the parent element, but i wanted it to be the same size as the column gap.
Is there a way to make the row gap the same size as the column gap?

First, it's better to use fr instead of percentage then you can rely on vw unit like below:
.parent {
margin: 30px 30px 0 30px;
display: block;
}
.grid {
display: grid;
border: 1px solid;
grid-template-rows: 55fr 45fr;
grid-template-columns: 20fr 48fr 30fr;
grid-gap: calc((100vw - 60px)/100);
}
.grid>div {
min-height: 100px;
height:100%;
background: red;
}
<div class="parent">
<div class="grid">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
below to compare
<div class="grid" style="grid-gap:1%;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>

Try using the rem unit. For example, gap: 2rem;
This will make both row and column size equal to the root element's font size.

Related

Using auto-fit, how do I make a 3-item grid that may have 1 or 3 columns but never 2 columns? [duplicate]

Looked into a few questions here but they don't quite solve what I'm looking for.
Say I have a website and I want. On desktop I want this:
This is easy. grid-template-columns: repeat(3, 33%) (basically)
On mobile, however, I want this
What I'm running into is happens before it flips to a single column:
I'm trying clamp(), minmax(), and all sorts of things but nothing ever works as I want. Yes, I can totally use a media query but I was hoping to create a truly fluid grid/flex layout using modern CSS like clamp, grid, minmax, etc so there wouldn't be a need for media queries for basic layout changes.
I know this doesn't work but as a starting point as requested here's a simple version of one of my 100 attempts :) In this version I was trying to use clamp to switch from a repeat(3) to repeat(1).
.wrapper {
display: grid;
gap: 15px;
grid-template-columns: repeat(clamp(1, calc(100% - 500px), 3), 33%);
}
.one {
background: red;
}
.two {
background: green;
}
.three {
background: blue;
}
<div class="wrapper">
<div class="item one"><h3>Example A</h3></div>
<div class="item two"><h3>Example Two</h3></div>
<div class="item three"><h3>Third Example</h3></div>
</div>
Full article with more generic rules: https://css-tricks.com/responsive-layouts-fewer-media-queries/
Here is an idea using max(0px, (400px - 100vw)*1000) inside flex-basis. This formula will eiter give 0px if 100vw (screen size) is bigger than 400px or a very big value in the opposite case giving each element a big flex-basis and create a wrapping. Simply adjust the 400px which play the role of #media (max-width:400px)
.container {
display:flex;
flex-wrap:wrap;
}
.container div {
height:100px;
border:2px solid;
background:red;
flex-basis:max(0px, (400px - 100vw)*1000);
flex-grow:1;
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
Using CSS grid it can be like below:
.container {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(clamp(30%, (400px - 100vw)*1000, 100%),1fr));
grid-gap:5px;
}
.container div {
height:100px;
border:2px solid;
background:red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
</div>
A similar question where I am controling the maximum number of columns without media query: CSS grid - maximum number of columns without media queries
We can scale the above solution to consider more complex cases.
Example of moving from 6 to 3 to 1 column:
.container {
display:grid;
grid-template-columns:
repeat(auto-fill,
minmax(clamp(clamp(15%,(800px - 100vw)*1000, 30%), (400px - 100vw)*1000, 100%)
/* if(screen> 800px) 15% elseif(screen> 400px) 30% else 100% */
,1fr));
grid-gap:5px;
}
.container div {
height:100px;
border:2px solid;
background:red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
To understand the values consider the following ranges:
100%/7 100%/6 100%/5 100%/4 100%/3 100%/2 100%/1
14.3% 16.7% 20% 25% 33.3% 50% 100%
To get 6 columns we need a value in the range ]14.3% 16.7%] (I considered 15%)
To get 3 columns we need a value in the range ]25% 33.3%] (I considered 30%)
We simply avoid the edges to make sure we account for the gaps.
A more generic solution using CSS variables where I will add 0.1% to make sure the value is big enough to get the needed number of column and it can hold the gap.
Let's also add some dynamic coloration (related: How to change the color of <div> Element depending on its height or width?)
.container {
/* first breakpoint*/
--w1:800px;
--n1:6;
/* second breakpoint*/
--w2:400px;
--n2:3;
display:grid;
grid-template-columns:
repeat(auto-fill,
minmax(clamp(clamp(100%/(var(--n1) + 1) + 0.1%, (var(--w1) - 100vw)*1000,
100%/(var(--n2) + 1) + 0.1%), (var(--w2) - 100vw)*1000,
100%), 1fr));
grid-gap:5px;
margin:10px 0;
}
.container div {
height:100px;
border:2px solid;
background:
linear-gradient(blue 0 0) 0 /1% calc(var(--w2) - 100vw),
linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;grid-gap:10px;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:600px;--n1:4;--n2:2;grid-gap:2vw;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Using flexbox where we can have a different (probably wanted) behavior where the last item of a row will take all the free space:
.container {
/* first breakpoint*/
--w1:800px;
--n1:6;
/* second breakpoint*/
--w2:400px;
--n2:3;
display:flex;
flex-wrap:wrap;
margin:10px 0;
}
.container div {
height:100px;
border:2px solid;
margin:5px;
flex-basis:clamp(clamp(100%/(var(--n1) + 1) + 0.1% ,(var(--w1) - 100vw)*1000,
100%/(var(--n2) + 1) + 0.1%),(var(--w2) - 100vw)*1000,
100%);
flex-grow:1;
box-sizing:border-box;
background:
linear-gradient(blue 0 0) 0 /1% calc(var(--w2) - 100vw),
linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
red;
}
<div class="container">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="container" style="--w1:600px;--n1:4;--n2:2;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
You can achive this by using grid like this:
.btnContainer {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); /* here you set when the width should change to be moved to the next row, in this example, the divs will move when the screen reduces size and their width is less than 200px */
}
.btnCenter3 {
background-color: rgb(6, 198, 247);
height: 400px;
}
.btnCenter4 {
height: 400px;
background-color: rgb(196, 95, 1);
}
.btnCenter5 {
height: 400px;
background-color: rgb(192, 231, 19);
}
<div class="btnContainer">
<div class="btnCenter3"></div>
<div class="btnCenter4"></div>
<div class="btnCenter5"></div>
</div>
#Temani's answer is bonkers but great :). I needed to implement a similar thing for a 4 column layout (breaking to 2 cols then 1 col) but found that replacing the 15 and 30 percentage values for 25 and 50 didn't work. This seems to be related to the fact that the percentages need to take account of the grid gap, so #Temani's answer only really works because of the rounding 'error'. So a more robust (if even more bonkers) solution, based on a 4 col grid is:
:root {
--grid-gap: 10px;
--grid-gap-x2: calc(var(--grid-gap));
}
.container {
display:grid;
grid-gap: var(--grid-gap-x2);
grid-template-columns:
repeat(auto-fill, minmax(clamp(clamp(calc(25% - var(--grid-gap-x2)),(800px - 100vw)*1000, calc(50% - var(--grid-gap-x2))), (400px - 100vw)*1000, 100%)
/* if(screen> 800px) 25% elseif(screen> 400px) 50% else 100%. */
/* (Subtracting grid gap from either side of percentage width.) */
,1fr));
}

4x4 grid of squares that scale up to a maximum width

How should I edit the CSS and/or HTML so that these squares fit to a particular maximum width, while maintaining the 4x4 square structure? Right now, it resizes to the width of the browser window, but if the browser is stretched out across the screen, the squares are far too large and the height goes well beyond the height of my screen.
I've tried adding a container div and adding a max-width, but that does not seem to relate to the width of 4 squares next to each other, and changes the width of each square without adjusting the height evenly.
.w {
overflow: hidden;
}
section {
margin: -1%;
padding: 20px;
}
section div {
background: #CCC;
float: left;
height: 24vw;
margin: 1%;
width: 23%;
color:white;
}
<div id="playGrid" class="w">
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>
How about, you know, CSS grid? You can use the width and height to adjust the whole shebang's size.
#playGrid {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr 1fr;
gap: 15px;
align-content: stretch;
width: 50vw;
height: 50vw;
}
#playGrid div {
background: #CCC;
color: white;
}
<div id="playGrid" class="w">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
<div>14</div>
<div>15</div>
<div>16</div>
</div>
You can leverage CSS Grid Layout to define your grid, and then bound the height and width of the section to 100vh:
#playGridSection {
display: grid;
grid-template-columns: repeat(4, 25%);
grid-template-rows: repeat(4, 25%);
height: 100vh;
width: 100vh;
margin-right: auto;
margin-left: auto;
}
section div {
background: #CCC;
color:white;
align-self: stretch;
justify-self: stretch;
margin: 1vh;
}
<div id="playGrid">
<section id="playGridSection">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>
You may relay on flex and a pseudo to stretch your element to a square boxe.
Here is a basic example. (You should also clarify what kind of content should be standing inside and which kind of layout you need, so we can tune/update HTML(the content to put inside) & CSS according to your real expected result, it could be like a sudoku grid ? Responsive grid of squares within a responsive grid of squares )
body {margin:0;}
.w {}
section {
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
padding: 20px;
max-width: 100vmin;
margin: auto;
}
section div {
background: #CCC;
min-width: 21%;
/* cannot be more than 4 on a row */
flex-grow: 1;
/* stretch their width evenly */
margin: 1vmin;
}
section div:before {
/* note, you need to stretch only one per row and
the selector can be also : section div:nth-child(4n):before */
content: '';
padding-top: 100%;
/* stretch height using width as a reference (padding/margin units in % ) */
float: left;
/* let it on the side to add content .. aside */
}
<div id="playGrid" class="w">
<section>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</section>
</div>

Is it possible to place all the items in grid in one row when I don't know the number of columns?

I'm trying to make a grid container that has undefined number of columns and I want it to be one row. Is there any way to do this in CSS?
.grid {
display: grid;
grid-gap: 5px;
}
.grid > div {
background: #ccc;
min-height: 100px;
}
<div class="grid">
<div></div>
<div></div>
<div></div>
</div>
There is two ways actually.
Using grid-template-columns: repeat(auto-fit, minmax(1px, 1fr));. Fits new columns automatically and determines it's mimimum and maximum width. More about Grid Template Columns and auto-fit/auto-fill.
Using grid-auto-flow: column;. Determines automatically placement behavior of grid cells. More about Grid auto flow.
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(1px, 1fr));
grid-gap: 5px;
margin-bottom: 5px;
}
.grid2 {
display: grid;
grid-auto-flow: column;
grid-gap: 5px;
margin-bottom: 5px;
}
.grid > div, .grid2 > div {
background: #ccc;
min-height: 100px;
}
<div class="grid">
<div></div>
<div></div>
<div></div>
</div>
<div class="grid2">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

How to align half div with css grid?

I have four divs. How do I align the second and third in one line? (50% each)
I have tried to do the following:
.wrap { display:grid; grid-template-columns:1fr; grid-template-rows:1fr "auto auto" 1fr; }
.wrap > div {border:1px solid; background:#4472C4;}
<div class="wrap">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
But chrome doesn't apply this style. maybe I am doing this wrong.
How do I fix it?
grid-template-rows:1fr "auto auto" 1fr;
This is nonsense. grid-template-rows provides a template for the size of each column in every row.
It doesn't describe each row one by one.
"auto auto" is not a valid size.
Create a 2x3 grid, then make the first and last elements span multiple cells in it.
div {
border: solid #aaa 1px
}
.grid-container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-template-areas: "Top Top" "Left Right" "Bottom Bottom";
}
.Top {
grid-area: Top;
}
.Left {
grid-area: Left;
}
.Right {
grid-area: Right;
}
.Bottom {
grid-area: Bottom;
}
<div class="grid-container">
<div class="Top">Top</div>
<div class="Left">Left</div>
<div class="Right">Right</div>
<div class="Bottom">Bottom</div>
</div>
You can specify a grid of two columns, and set grid-column: span 2 for the items you want to have full width.
.wrap {
display: grid;
grid-template-columns: 1fr 1fr;
}
.wrap>div {
border: 1px solid;
background: #4472C4;
min-height: 2em;
margin:0.3em;
}
.wrap>div:nth-child(3n+1) {
grid-column: span 2;
}
<div class="wrap">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>

Is it possible to explicitly make a grid item appear always on the last row or last column?

I want to place a grid item to be always on the last row and / or on the last column of a grid. Even if I don't know how many rows or columns the grid might have. Is something like that possible?
This would be my grid:
.columns {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min-content, 16.5rem));
grid-gap: 1rem;
}
I only found placement by explicit rows or columns:
MDN
Following my comment; from https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Line-based_Placement_with_CSS_Grid#Counting_backwards
We can also count backwards from the block and inline end of the grid, for English that would be the right hand column line and final row line. These lines can be addressed as -1, and you can count back from there – so the penultimate line is -2.
You can use a pseudo element :after to place an element at the end of the grid - see demo below:
.columns {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min-content, 16.5rem));
grid-gap: 1rem;
}
.columns div {
border: 1px solid;
height: 100px;
}
.columns:after {
content:'';
display: block;
border: 1px solid red;
height: 100px;
}
<div class="columns">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
Or you can use order property to place the element to the end - if any other grid item has order property, just give a large value. See demo below:
.columns {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min-content, 16.5rem));
grid-gap: 1rem;
}
.columns div {
border: 1px solid;
height: 100px;
}
.columns .last {
order: 1;
border: 1px solid red;
}
<div class="columns">
<div></div>
<div></div>
<div></div>
<div class="last"></div>
<div></div>
<div></div>
<div></div>
</div>