How to create CSS grid system with merged cells - css

I'm trying to achieve the following layout:
As you can see, the cards in the middle column occupy multiple grids, in order to give it that effect.
What I have:
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
gap: 0px 0px;
grid-template-areas:
". . ."
". . ."
". . .";
}
.grid-item {
border: 1px solid black;
}
.grid-item:nth-child(3) {
grid-column: 2;
grid-row: 2;
}
.grid-item:nth-child(4) {
grid-column: 2;
grid-row: 3;
}
.grid-item:nth-child(5) {
grid-column: 2;
grid-row: 4;
}
.grid-item:nth-child(6) {
grid-column: 3;
grid-row: 1;
}
<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>
However, my approach definitely isn't the most sustainable, nor are my cards rendering in the correct order (cards go from 1, 7, 2, 3 etc ..).
I haven't seen an approach where using CSS grid, a layout like the image has been achieved, so wondering if CSS grid is the best solution here?

To achieve this you mostly have to change the behavior of your grid container.
Adding grid-auto-flow: column; fixes the issue of the elements moving in rows.
Doubling the number of rows means that you can work "by halves" when positioning our elements.
On the grid elements, adding grid-row: span 2 sets them to occupy a whole area in your design
Then all you have to do is tell the first one and second to last one to start on the second row.
If you were going to iterate this over more than 3 columns, it would by every 7th element minus the first one ( .grid-item:nth-child(7n-1)) instead of nth-to-last. In that case, you'd also have to define your grid differently, similar to below.
grid-template-rows: repeat( 6, auto );
grid-auto-columns: 1fr;
You can also remove the grid-area definition.
.grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: repeat(6, auto);
grid-auto-flow: column;
gap: 0px 0px;
}
.grid-item {
border: 1px solid black;
grid-row: span 2;
}
.grid-item:nth-child(1), .grid-item:nth-last-child(2) {
grid-row: 2 / span 2;
}
<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>

Related

Grid layout, need 3 divs to occupy 2 columns and a row

I have the following markup:
<div class="wrapper">
<div class="one">One</div>
<div class="two">Two</div>
<div class="three">Three</div>
</div>
I want the layout to accomplish a layout in which the first two child divs are arranged next to each other as two columns while the 3rd sits on a row of its occupying full width.
The first child column will be a fixed width (30px), while the second should occupy the remaining space.
I have tried this, but it doesn't accomplish what I need:
.wrapper {
display: grid;
grid-template-columns: 20px auto 100%;
border:1px solid white;
}
Maybe something like this
.wrapper {
display: grid;
grid-template-columns: 30px 1fr;
grid-gap: 1rem;
}
.child {
padding: 1rem;
border: 1px solid red;
display: flex;
align-items: center;
justify-content: center;
}
.three {
grid-column: 1 / -1; /* 👈 It makes this element take all available columns (the whole row)
}
<div class="wrapper">
<div class="child one">One</div>
<div class="child two">Two</div>
<div class="child three">Three</div>
</div>
That's the method I prefer.
First, you fraction in four with grid-template: 1fr 1fr / 1fr 1fr. This is column sizes / row sizes
After that, imagine you have two squares together in the first row (first 1fr 1fr)
Now imagine the three lines (The first line of the left square draws one vertical line, the two squares touching draw a second line, and the 2nd square draws the third one).
|â–¢|â–¢|
So, you say to #red, start in line 1 and finish in line 2 grid-column: 1 / 2, to the #green, start in the two and finish in the 3, and so on.
The result looks like this:
.grid
{
display: grid;
grid-auto-flow: row dense;
/* This is column column / row row */
grid-template: 1fr 1fr / 1fr 1fr;
height: 300px;
}
#red {
background-color: red;
grid-column: 1 / 2;
grid-row: 1 / 2;
}
#green {
background-color: green;
grid-column: 2 / 3;
grid-row: 1 / 2;
}
#blue {
background-color: blue;
grid-column: 1 / 3;
grid-row: 2 / 3;
}
/* To make the first row 30px you can use this instead */
.grid
{
grid-template: 1fr 1fr / 30px 1fr;
}
<div class="grid">
<div id="blue">Blue</div>
<div id="red">Red</div>
<div id="green">Green</div>
</div>

Overlapping Grid Elements: 2nd div fails to load

Both divs display correctly alone, but if both img-1 and img-2 divs are both in the container, the second div disappears.
HTML:
<div class="body-background">
<div class="background-img-1"></div>
<div class="background-img-2"></div>
</div>
CSS
.body-background {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: 1fr;
width: 100%;
height: 100%;
}
.background-img-1 {
background: red;
grid-column: 1 / 3;
}
.background-img-2 {
background: blue;
grid-column: 2 / 4;
}
Shouldn't the boxes overlap normally?
Give both background divs a grid-row: 1 property (which becomes grid-row: 1 / 2). I don't think the browser likes having to give it implicitly to two overlapping cells.
.body-background {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: 1fr;
width: 100vw;
height: 100vh;
}
.background-img-1 {
background-color: red;
grid-column: 1 / 3;
grid-row: 1;
}
.background-img-2 {
background-color: blue;
grid-column: 2 / 4;
grid-row: 1;
}
<div class="body-background">
<div class="background-img-1"></div>
<div class="background-img-2"></div>
</div>

How to make a grid item stretch to full width if next element is hidden?

guys. I'm trying to understand CSS Grid and found a behaviour I thought would be simple but turned out to be a little complicated.
I need to follow a 12-column layout a have a row with 2 elements but I need these elements to fill 100% of the width if it is the single element.
I tried to use auto-fit and it almost did the job but I couldn't find a way to explicitly set 12 columns this way.
Here's a snippet of my code:
<div class="autofit">
<div class="content"></div>
<div class="banner"></div>
</div>
.autofit {
display:grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
grid-gap: 20px;
text-align: center;
}
.autofit .content{
grid-column: 1/9;
}
.autofit .banner {
grid-column: 10/-1;
}
This way the grid works as expected but if I delete the .banner element the .content doesn't stretch to fill the available space ):
Use :only-child to define and extra rule:
.autofit {
display: grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
grid-gap: 20px;
text-align: center;
margin:5px;
}
.autofit > *{
height:20px;
}
.autofit .content {
grid-column: 1/9;
background:red;
}
.autofit .banner {
grid-column: 10/-1;
background:blue;
}
.autofit > :only-child{
grid-column: 1/-1;
}
<div class="autofit">
<div class="content"></div>
<div class="banner"></div>
</div>
<div class="autofit">
<div class="content"></div>
</div>
<div class="autofit">
<div class="banner"></div>
</div>
You try this.
.grid-container {
display: grid;
}
.grid-container--fit {
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
}
.grid-container div{background:#ff0000;}
<div class="autofit grid-container grid-container--fit">
<div class="content">test</div>
<div class="banner">test</div>
</div>
Auto fit
<div class="autofit grid-container grid-container--fit">
<div class="content">test</div>
</div>

How do you place an element on the bottom right corner of a CSS Grid? [duplicate]

This question already has answers here:
Make a grid item span to the last row / column in implicit grid
(5 answers)
Closed 5 years ago.
I have a CSS grid such as this:
.grid-wrapper
display: grid
margin: 0 auto
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr))
grid-auto-rows: minmax(100px, auto)
grid-gap: 10px
And I want to position a main element in the beginning:
.main-item
grid-column-end: span 2
grid-row-end: span 2
A series of intermediate elements following that one, and in the last possible position of the grid -not following the other elements, but literally on the right bottom corner of the grid-.
Right now I can place it on the last column with
.last item
grid-column-end: -1
But I can't find a way of placing it on the last row -given that the number of rows is not defined-.
Any ideas?
https://codepen.io/rtyx/pen/XVQMJQ
.wrapper {
border: 2px solid #f76707;
background-color: #fff4e6;
}
.wrapper>div {
border: 2px solid #ffa94d;
background-color: #ffd8a8;
color: #d9480f;
}
.wrapper {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
grid-auto-rows: minmax(100px, auto);
grid-gap: 10px;
width: 1000px;
}
.main-item {
grid-column-end: span 2;
grid-row-end: span 2;
}
.last-item {
grid-column-end: -1;
grid-row-end: -1;
}
<div class="wrapper">
<div class="main-item">Main item</div>
<div class="item1">Item 2</div>
<div class="item2">Item 3</div>
<div class="item3">Item 4</div>
<div class="last-item">last-item</div>
</div>
Based on your codepen. In class .last-item set grid-row-end:3
For same layout use this...
.last-item {
grid-column-end: -1;
grid-row-end: 4;
}

How to get grid areas to have document flow?

I have a CSS Grid with two areas (left & right). I want to put multiple spans inside these areas, but when I do the following, the items appear on top of each other, as if they were taken out of document flow.
How do I put them back into document flow, so they appear next to each other?
div {
display: grid;
grid-template: 1fr 1fr / 1fr;
grid-template-areas: "left right"
}
div .left {
grid-area: left;
}
div .right {
grid-area: right;
}
<div>
<span class="left">First</span>
<span class="left">Second</span>
<span class="left">Third</span>
<span class="right">Fourth</span>
<span class="right">Fifth</span>
</div>
Codepen
Full On Grid
Grids are all about columns and rows, so the version without area names (which are only an alias for a location) is:
div {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 50px 50px 50px;
}
div .left {
grid-column: 1/1;
}
.la {
grid-row: 1/1;
}
.lb {
grid-row: 2/2;
}
.lc {
grid-row: 3/3;
}
div .right {
grid-column: 2/2;
}
<div>
<span class="left la">First</span>
<span class="left lb">Second</span>
<span class="left lc">Third</span>
<span class="right la">Fourth</span>
<span class="right lb">Fifth</span>
</div>
Two Columns, Spans Wherever!
If you just want "two columns" and don't care about positioning the span elements, this might be better for you.
.grid {
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: auto;
}
.left {
grid-column: 1/1;
grid-row: 1/1;
}
.right {
grid-column: 2/2;
grid-row: 1/1;
}
span {
display: block;
}
<div class="grid">
<div class="left">
<span>First</span>
<span>Second</span>
<span>Third</span>
</div>
<div class="right">
<span>Fourth</span>
<span>Fifth</span>
</div>
</div>
Each grid item must get a unique grid-area name.
If you apply the same name to multiple elements then, per the cascade, the last item will be displayed, overlaying the others with the same name.
Here's an example of a proper set-up just for illustration purposes:
div {
display: grid;
grid-template-areas: "left1 right1"
"left2 right2"
"left3 right3"
"left4 right4"
"left5 right5";
}
span:nth-child(1) { grid-area: left1; }
span:nth-child(2) { grid-area: left2; }
span:nth-child(3) { grid-area: left3; }
span:nth-child(4) { grid-area: right1; }
span:nth-child(5) { grid-area: right2; }
<div>
<span>First</span>
<span>Second</span>
<span>Third</span>
<span>Fourth</span>
<span>Fifth</span>
</div>
It appears that you're looking for a vertically flowing grid that wraps after the third row. In that case, here's all you need:
div {
display: grid;
grid-template: repeat(3, auto) / 1fr 1fr;
grid-auto-flow: column;
}
<div>
<span>First</span>
<span>Second</span>
<span>Third</span>
<span>Fourth</span>
<span>Fifth</span>
</div>
Learn more about grid-auto-flow: column here: Make grid container fill columns not rows

Resources