Collapse or merge grid cells if content is not there - html

If I have a grid like this:
Is there a way to automatically push the grid item 3 up to take the space of grid item 1?
Structure:
<div id="1"></div>
<div id="2">Content</div>
<div id="3">Content</div>
For grid item 2 I do this:
grid-row: 1 / span 2;
But i cannot do that for grid item 3 because then if there is content in item 1, it overlaps it. And in my case I do not know if there is content or not

It's almost automatic. Set for div2 the column 2 and the rows 1-2. And let the other divs to occupy the remaining space freely:
.container {
display: grid;
grid-template-columns: auto auto;
border: solid 1px red;
margin: 10px;
}
#div2 {
grid-row: 1 / span 2;
grid-column: 2;
background-color: yellow;
}
<div class="container">
<div id="1"></div>
<div id="div2">Content</div>
<div id="3">Content</div>
</div>
<div class="container">
<div id="1">1</div>
<div id="div2">Content</div>
<div id="3">Content</div>
</div>

Related

Is it possible to grid bootstrap vertically?

It seems that bootstrap can only produce horizontal grid systems which is making it hard for me to try develop a project. Here's what I am trying to do:
My page is divided into 4 sections, the leftside height of each blocks are different to the height of the rightside blocks.
I want to make the leftside have the same equal height while the right side has a different height each width which I can do when the grid is a horizontal system.
I want box1 and box2 to be the same height (vh-50) and then box3 to have the equal height.
my desired grid layout:
I've tried doing it like this but it doesn't work and look horrible.
#infoBox {
height: 50vh;
width: 60vh;
}
#tracklistBox {
height: 60vh;
width: 40vh;
}
#playBox {
height: 50vh;
}
#episodesBox {
height: 40vh;
}
<body class="d-flex flex-column min-vh-100">
<div class="container-fluid">
<div class="row ">
<div id="infoBox" class="col border">
1 of 2
</div>
<div id="tracklistBox" class="col border">
2 of 2
</div>
</div>
<div class="row">
<div id="playBox" class="col border">
1 of 3
</div>
<div id="episodesBox" class="col border">
2 of 3
</div>
</div>
</div>
</body>
It's not bootstrap but you can use the grid system
.parent {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: repeat(5, 1fr);
grid-column-gap: 0px;
grid-row-gap: 0px;
}
.div1 {
grid-area: 1 / 1 / 3 / 3;
background-color: aqua;
}
.div2 {
grid-area: 3 / 1 / 5 / 3;
background-color: yellow;
}
.div3 {
grid-area: 1 / 3 / 4 / 4;
background-color: violet;
}
.div4 {
grid-area: 4 / 3 / 5 / 4;
background-color: greenyellow;
}
<div class="parent">
<div class="div1">Box 1</div>
<div class="div2">Box 2</div>
<div class="div3">Box 3</div>
<div class="div4">Box 4</div>
</div>

Make a grid as big as the screen

I need the grid ad big as the page (it should touch the top the bottom and both sides) and I'd like it to be non-scrollable.
HTML:
<div class="wrapper">
<div class="prova">One</div>
<div class="prova"> </div>
<div class="prova">Three</div>
<div class="prova">Four</div>
<div class="prova"> five </div>
<div class="prova">Six</div>
<div class="prova">Seven</div>
<div class="prova">Eight</div>
<div class="prova">Nine</div>
<div class="prova">Ten</div>
<div class="prova">Eleven</div>
<div class="prova">Twelve</div>
</div>
CSS:
.wrapper {
padding-top: 10%;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
}
.prova{
border: 1px solid;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
I've read multiple questions but I couldn't find any solution that works fine for me.
As you can see in the picture above the grid doesn't touch neither the top or the bottom!
Set gird-auto-rows to use a percentage of the viewport height. Equal amounts per expected row. So in your case 25vh. Then remove any padding or margin around the grid.
html, body {
margin: 0
}
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 25vh;
width: 100%;
}
.prova{
border: 1px solid;
}
.wrapper div:nth-child(2) {
grid-column: 3;
grid-row: 2 / 4;
}
.wrapper div:nth-child(5) {
grid-column: 1 / 3;
grid-row: 1 / 3;
}
<div class="wrapper">
<div class="prova">One</div>
<div class="prova"> </div>
<div class="prova">Three</div>
<div class="prova">Four</div>
<div class="prova"> five </div>
<div class="prova">Six</div>
<div class="prova">Seven</div>
<div class="prova">Eight</div>
<div class="prova">Nine</div>
<div class="prova">Ten</div>
<div class="prova">Eleven</div>
<div class="prova">Twelve</div>
</div>
If you want it to touches the top just remove the padding
And for other sides just set the width and height of the wrapper to 100vh and 100vw

Why are some grid items appearing out of order?

I am working on a CSS grid layout that looks something like this: https://jsfiddle.net/ftL5zw0x/23/ where I don't know how many items I will have.
The layout looks how I want it to but the problem is with the ordering. Every 6th and 7th items appear out of order, they should switch places while the layout stays unchanged. (For example items 6 and 7)
Is there any way I can achieve this through CSS alone?
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
grid-gap: 8px;
}
.item {
background-color: #c4c4c4;
display: flex;
justify-content: center;
align-items: center;
}
div:nth-child(8n+1),
div:nth-child(8n+3),
div:nth-child(8n+7),
div:nth-child(8n+8) {
grid-row: span 1;
}
div:nth-child(8n+2),
div:nth-child(8n+4),
div:nth-child(8n+5),
div:nth-child(8n+6) {
grid-row: span 2;
}
<div class="wrapper">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
<div class="item">item4</div>
<div class="item">item5</div>
<div class="item">item6</div>
<div class="item">item7</div>
<div class="item">item8</div>
<div class="item">item9</div>
<div class="item">item10</div>
<div class="item">item11</div>
<div class="item">item12</div>
<div class="item">item13</div>
<div class="item">item14</div>
<div class="item">item15</div>
<div class="item">item16</div>
</div>
First change your selectors that is the 7th element that should span not the 6th
This will push the 6th element to the right following the flow of the grid that is being the position of the previous element 5th
However we can enforce the position of every 6th element because we know it's the second column.
That will make the 7th and 8th element follow the 6th element we can fix this with grid-auto-flow:row dense;
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
grid-auto-flow: row dense;
grid-gap: 8px;
}
.item {
background-color: #c4c4c4;
display: flex;
justify-content: center;
align-items: center;
}
div:nth-child(8n+1),
div:nth-child(8n+3),
div:nth-child(8n+6),
div:nth-child(8n+8) {
grid-row: span 1;
}
div:nth-child(8n+2),
div:nth-child(8n+4),
div:nth-child(8n+5),
div:nth-child(8n+7) {
grid-row: span 2;
}
div:nth-child(8n+6) {
grid-column: 2;
}
<div class="wrapper">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
<div class="item">item4</div>
<div class="item">item5</div>
<div class="item">item6</div>
<div class="item">item7</div>
<div class="item">item8</div>
<div class="item">item9</div>
<div class="item">item10</div>
<div class="item">item11</div>
<div class="item">item12</div>
<div class="item">item13</div>
<div class="item">item14</div>
<div class="item">item15</div>
<div class="item">item16</div>
</div>
Although every 6th and 7th item appear out of order, they are not out of order.
Look at item 5 (a span 2 item). The top half is on row 2 and the bottom half is on row 3. But it gets placed on row 2.
Same for item 6. The top half is on row 2 and the bottom half is on row 3. It gets placed on row 2, which comes before row 3, which is where item 7 gets placed.
So, 6 is placed before 7, 15 is before 16, etc., and everything is placed in order.
Targeting these items with CSS is not a big deal.
div:nth-child(8n+6),
div:nth-child(8n+7) {}
.wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 100px;
grid-gap: 8px;
}
.item {
background-color: #c4c4c4;
display: flex;
justify-content: center;
align-items: center;
}
div:nth-child(8n+1), div:nth-child(8n+3), div:nth-child(8n+7), div:nth-child(8n+8) {
grid-row: span 1;
}
div:nth-child(8n+2), div:nth-child(8n+4), div:nth-child(8n+5), div:nth-child(8n+6) {
grid-row: span 2;
}
div:nth-child(8n+6),
div:nth-child(8n+7) {
background-color: lightgreen;
}
<div class="wrapper">
<div class="item">item1</div>
<div class="item">item2</div>
<div class="item">item3</div>
<div class="item">item4</div>
<div class="item">item5</div>
<div class="item">item6</div>
<div class="item">item7</div>
<div class="item">item8</div>
<div class="item">item9</div>
<div class="item">item10</div>
<div class="item">item11</div>
<div class="item">item12</div>
<div class="item">item13</div>
<div class="item">item14</div>
<div class="item">item15</div>
<div class="item">item16</div>
</div>
But then what? Not sure there's any easy solution to the problem, but this one looks quite good.

Grid align horizontal center is not works

.parent{
border:1px solid red;
display:grid;
grid-template-columns: repeat(12, 1fr);
}
.child{
background:green;
align-self:center;
}
<div class="parent">
<div class="child" style="justify-self: center;">
I am child
</div>
</div>
I am looking a solution to let child should align itself to center. so i can create a class name for left, right, and center will use across.
What's happening here for you is automatic grid placement. Technically speaking the item is aligned to the center inside the first column you created. The problem is that it ends up all the way on the left because that's where your first column actually is.
There's a few ways you can approach this if you want to continue using CSS Grid for this layout concept. But the problem with a 12 col grid is that there won't be a "center" without some offsetting or transforms.
I recommend you use the following if you really only need one row with 3 possible placements. It's a 13 col grid with a defined height of a single row, this ensures if the items are being shuffled out of order (if left is second like my example) that they won't jump to a second implied row.
.parent{
border:1px solid red;
display:grid;
grid-template-columns: repeat(13, 1fr);
grid-template-rows: 60px;
}
.center{
background:green;
grid-column: 7/8;
grid-row: 1/2;
}
.left {
background: red;
grid-column: 1/2;
grid-row: 1/2;
}
.right {
background: blue;
grid-column: 13/14;
grid-row: 1/2;
}
<div class="parent">
<div class="center">
I am child
</div>
<div class="left">
Me too
</div>
<div class="right">
Also me
</div>
</div>
Edit: You can also use flexbox and drop some of the complexity and get better responsiveness by using the order property and justifying the content as space-between.
.parent {
border: 1px solid red;
display: flex;
justify-content: space-between;
}
.center {
background: green;
order: 2
}
.left {
background: red;
order: 1
}
.right {
background: blue;
order: 3
}
<div class="parent">
<div class="center">
I am child
</div>
<div class="left">
Me too
</div>
<div class="right">
Also me
</div>
</div>
Here is an optimized version with flexible values that can work with any number of columns.
I will consider CSS variables to easily adjust the template and the center element. For the left and right we only need 1 and -1
.parent{
--n:6;
display:grid;
grid-template-columns: repeat(calc(2*var(--n)), 1fr);
grid-auto-flow:dense;
margin:5px;
outline:1px solid;
}
.left{
grid-column-start:1;
}
.right{
grid-column-end:-1;
text-align:right;
}
.center {
grid-column:calc(var(--n))/span 2;
text-align:center;
}
.parent > * {
border:1px solid red;
}
<div class="parent">
<div class="left">
left
</div>
<div class="right">
right
</div>
<div class="center">
center
</div>
</div>
<div class="parent" style="--n:3">
<div class="left">
left
</div>
<div class="right">
right
</div>
<div class="center">
center
</div>
</div>
<div class="parent" style="--n:10">
<div class="left">
left
</div>
<div class="right">
right
</div>
<div class="center">
center
</div>
</div>
.parent {
border: 1px solid red;
display: grid;
grid-template-columns: repeat(1, 1fr);
}

How to prevent grid-row span from changing column placement?

I have a 3 X 3 CSS Grid.
I have a row in which I have three items A, B & C.
I want item C to have a rowspan of 2.
To do so, I am using grid-row: 1 / span 2;. It is taking two rows, but it's being placed in the first column instead of simply lying in the 3rd column. I don't know why this is happening.
I want item C to stay at the place where it is in the HTML.
One work around to this problem is to explicitly setting grid-column: 3 / span 1 which I don't want to do. I want items to be placed the way they are in HTML.
Is there any way to suppress this behavior?
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
Another way of solving it (That points to the reason why is stating a row for the other items):
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
background: orange;
}
.b {
grid-row: 1;
}
<div class="grid-container">
<div class="b">
<h1>A</h1>
</div>
<div class="b">
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
And the reason of this behaviour is that the more restrictive elements get positioned first. This way, the possibilities of the grid algorithm to achieve a solution are bigger.
That is, an element that has a requirement will be positioned first, elements that don't have a requirement last.
Steps 2 (for a item) and 4 (for the remaining items) in this part of the spec
If only one gets stock to a row number it will come first and stick there ahead in the flow. To avoid this, other grid items needs to be set to a defaut row as well.
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
div {
grid-row: 1;/* here is the basic fix but will set each item on first row */
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
Else you need also to tell in which grid-column it should stand
.a {
grid-row: 1 / span 2;
grid-column:3;
background: orange;
}
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: 1 / span 2;
grid-column:3;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
or let auto placement do its job while only setting how many rows to span, wich is here, in my own opinion, the most flexible way with a minimum of css rules/selector to set, too much grid kills grid :) , make it simple :
.a {
grid-row: span 2;
background: orange;
}
snippet with a few example letting the .aclass do its job without setting the column nor the row number where to stand, it will just be spanning where it stans in the flow
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(3, 1fr);
}
h1 {
border: 2px solid;
padding: 0;
margin: 0;
font-size: 20px;
}
.a {
grid-row: span 2;
background: orange;
}
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
</div>
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div class="a">
<h1>B</h1>
</div>
<div>
<h1>C</h1>
</div>
</div>
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div>
<h1>C</h1>
</div>
<div>
<h1>D</h1>
</div>
<div>
<h1>E</h1>
</div>
<div class="a">
<h1>F</h1>
</div>
<div>
<h1>G</h1>
</div>
<div>
<h1>H</h1>
</div>
</div>
<hr/>
<div class="grid-container">
<div>
<h1>A</h1>
</div>
<div>
<h1>B</h1>
</div>
<div class="a">
<h1>C</h1>
</div>
<div>
<h1>D</h1>
</div>
<div>
<h1>E</h1>
</div>
<div>
<h1>F</h1>
</div>
<div>
<h1>G</h1>
</div>
<div>
<h1>H</h1>
</div>
</div>
Clearly, there's something in the spec that causes this behavior. I'm not yet sure what it is. (Update: see #Vals' answer for an explanation.)
However, here's a valid and simple solution:
Instead of:
.a {
grid-row: 1 / span 2;
}
Use:
.a {
grid-row-end: span 2;
}
From the spec:
9.3. Line-based Placement: the grid-row-start,
grid-column-start, grid-row-end, and grid-column-end
properties
The grid-row-start, grid-column-start, grid-row-end, and
grid-column-end properties determine a grid item’s size and location
within the grid by contributing a line, a span, or nothing (automatic)
to its grid placement, thereby specifying the inline-start,
block-start, inline-end, and block-end edges of its grid area.
...
For example, grid-column-end: span 2 indicates the second grid line
in the endward direction from the grid-column-start line.
Also, consider this single rule that gives you full control and makes it all work:
.a {
grid-area: 1 / 3 / 3 / 4;
}
jsFiddle
The grid-area shorthand property parses values in this order:
grid-row-start
grid-column-start
grid-row-end
grid-column-end
Note the counter-clockwise direction, which is the opposite of margin and padding.