How would I create a grid that has this layout?
I tried something like this but obviously it's not working
.wrapper {
display: grid;
grid-template-areas: "i i i" "i i i" "i i i" ". i ."
}
<div class="wrapper">
<div class="inside">Hello</div>
<div class="inside">Hello</div>
<div class="inside">Hello</div>
<div class="inside">Hello</div>
<div class="inside">Hello</div>
<div class="inside">Hello</div>
</div>
I thought if I target the second to last card and create the space that way but can't figure out how to target each card to put in a separate grid.
You can use the grid-column property to position each grid item.
.grid-wrapper {
display: grid;
grid-template-columns: repeat(4, 100px);
grid-gap: 1em;
}
.grid-item {
background-color: dodgerblue;
height: 100px;
width: 100px;
border-radius: 10px;
}
#last-item-1 {
grid-column: 2 / 3; /* Start from column-line 2 and end at 3 */
}
#last-item-2 {
grid-column: 3 / 4; /* Start from column-line 3 and end at 4 */
}
<div class="grid-wrapper">
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item"></div>
<div class="grid-item" id="last-item-1"></div>
<div class="grid-item" id="last-item-2"></div>
</div>
You can go through this guide on CSS Grid.
If you don't have constraints on the width of the columns, doing this with flexbox is easier. Using the grid module is tricky to handle the latest child due to its "table-like" behavior, while with flex, you can do it with this:
div {
display: flex;
flex-wrap: wrap;
}
div > div {
background-color: hotpink;
height: 200px;
width: 200px;
margin: 30px auto;
}
<div>
<div>01</div>
<div>02</div>
<div>03</div>
<div>04</div>
<div>05</div>
<div>06</div>
<div>07</div>
<div>08</div>
<div>09</div>
<div>10</div>
</div>
Related
In the code below, I am trying to implement a grid made of 2 rows of 3 images in the bottom right corner only. The grid should not be bigger than the other quarters. In other words, I would like each quarter to be of the same size, but the bottom right one should have these 2 rows of 3 images.
My key objective is to have a method which collapses into a single column on small screens, with the images on top of each other. So on small screens, there shouldn't be any more grids, but just a column of images below the 3 quarters:
On normal screen:
| Hello World | 2 |
| | |
| 3 | img img img |
| | img img img |
On small screens:
Hello World
2
3
img
img
img
img
img
img
Here is my code, which does not work...
<!DOCTYPE html>
<html>
<head>
<style>
.box.md {
grid-column: span 2;
grid-row: span 2;
}
.box.lg {
grid-column: span 2;
grid-row: span 2;
}
.container {
padding: 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-auto-rows: 240px;
grid-auto-flow: dense;
grid-gap: 8px;
}
.box {
background: yellow;
display: flex;
justify-content: center;
align-items: center;
font-size: 48px;
font-weight: bold;
}
.grid-container {
display: grid;
grid-template-columns: auto auto auto;
}
.item1 {
grid-row-start: 1;
grid-row-end: 3;
}
</style>
</head>
<body>
<h1>Test:</h1>
<div class="container">
<div class="box md">
<p> Hello World </p>
</div>
<div class="box md">2</div>
</div>
<div class="container">
<div class="box md">3</div>
<div class="container">
<div class="row" >
<div class="grid-container">
<div class="item1">
<a><img src="AI.jpg"></a>
</div>
<div class="item2">
<a><img src="AI.jpg"></a>
</div>
<div class="item3">
<a><img src="AI.jpg"></a>
</div>
<div class="item4">
<a><img src="AI.jpg"></a>
</div>
<div class="item5">
<a><img src="AI.jpg"></a>
</div>
<div class="item6">
<a><img src="AI.jpg"></a>
</div>
</div>
</div>
</div>
</div>
.box.md {
grid-column: span 2;
grid-row: span 2;
}
.box.lg {
grid-column: span 2;
grid-row: span 2;
}
.container {
padding: 20px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
grid-auto-rows: 240px;
grid-auto-flow: dense;
grid-gap: 8px;
}
.box {
background: yellow;
display: flex;
justify-content: center;
align-items: center;
font-size: 48px;
font-weight: bold;
}
.grid-container {
display: grid;
grid-template-columns: auto auto auto;
}
.item1 {
grid-row-start: 1;
grid-row-end: 3;
}
<h1>Test:</h1>
<div class="container">
<div class="box md">
<p> Hello World </p>
</div>
<div class="box md">2</div>
</div>
<div class="container">
<div class="box md">3</div>
<div class="container">
<div class="row">
<div class="grid-container">
<div class="item1">
<a><img src="AI.jpg"></a>
</div>
<div class="item2">
<a><img src="AI.jpg"></a>
</div>
<div class="item3">
<a><img src="AI.jpg"></a>
</div>
<div class="item4">
<a><img src="AI.jpg"></a>
</div>
<div class="item5">
<a><img src="AI.jpg"></a>
</div>
<div class="item6">
<a><img src="AI.jpg"></a>
</div>
</div>
</div>
</div>
</div>
Could anyone help me solve this problem?
Kind regards,
-Pierre.
Using flex with wrap to layout your main "grid". Using grid with auto-fit columns to layout the pictures.
I did that because I suppose you are after a fluid layout. It would be much easier to adapt to any screen using media queries...
You should try the snippet in full-screen and test with various windows sizes. Pictures layout can be suited to your requirements by changing the pixel size in minmax(240px, 1fr) for .grid-container.
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.container > * {
flex: 1;
min-width: 300px;
min-height: 250px;
}
.box {
background: yellow;
display: flex;
justify-content: center;
align-items: center;
font-size: 48px;
font-weight: bold;
}
.grid-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
grid-auto-rows: minmax(120px, max-content);
gap: .5rem;
padding: .5rem;
}
.grid-container a {
display: flex;
align-items: center;
justify-content: center;
max-height: 100%;
max-width: 100%;
}
.grid-container img {
display: block;
max-width: 100%;
max-height: 100%;
}
<h1>Test:</h1>
<div class="container">
<div class="box md">
<p> Hello World </p>
</div>
<div class="box md">2</div>
</div>
<div class="container">
<div class="box md">3</div>
<div class="container">
<div class="row">
<div class="grid-container">
<div class="item1">
<a><img src="https://picsum.photos/seed/pic1/300/200"></a>
</div>
<div class="item2">
<a><img src="https://picsum.photos/seed/pic2/300/200"></a>
</div>
<div class="item3">
<a><img src="https://picsum.photos/seed/pic3/300/200"></a>
</div>
<div class="item4">
<a><img src="https://picsum.photos/seed/pic4/300/200"></a>
</div>
<div class="item5">
<a><img src="https://picsum.photos/seed/pic5/300/200"></a>
</div>
<div class="item6">
<a><img src="https://picsum.photos/seed/pic6/300/200"></a>
</div>
</div>
</div>
</div>
</div>
You coumd try something with calc() and clamp() to give a minmax() value to your columns dependind on a set px value to init calc(clamp()) ; and the unknown value that is 100vw. Playing around with those, it allows you to set a min and max-width while the calc() function updates with the viewport's width. It can give a failing value (if calculation turns out to be less than 0).
Once you understood how it worked, you can use your own values to reset your breakpoints without a mediaquerie but auto-fit.
Example setting every items as direct child of the container and using nested grid with different calc(clamp()) setting :
* {box-sizing:border-box;}
.container {
display:grid;
grid-template-columns: repeat(auto-fit,minmax(clamp(calc(((200px + 50vw ) * 2 ) - 100vw ), 40vw, 100% ) ,1fr));
gap:1em;
width:100%;
}
.box.md {
max-width:100%;
border:solid;
color:red;
justify-content:space-around;
}
.box.md.img {
width: 100%;
grid-template-columns: repeat(auto-fit,minmax(calc(((140px + 25vw) * 2) - 50vw) ,1fr));
}
.box.md.img img {
width:100%;
}
<h1>Test: grid layout</h1>
<div class="container">
<div class="box md">
<p> Hello World </p>
</div>
<div class="box md">2</div>
<div class="box md">3</div>
<div class="box md img container">
<div class="item1 box img ">
<a><img src="https://dummyimage.com/200x100/&text=AI.jpg"></a>
</div>
<div class="item2 box img">
<a><img src="https://dummyimage.com/200x100/&text=AI.jpg"></a>
</div>
<div class="item3 box img">
<a><img src="https://dummyimage.com/200x100/&text=AI.jpg"></a>
</div>
<div class="item4 box img">
<a><img src="https://dummyimage.com/200x100/&text=AI.jpg"></a>
</div>
<div class="item5 box img">
<a><img src="https://dummyimage.com/200x100/&text=AI.jpg"></a>
</div>
<div class="item6 box img">
<a><img src="https://dummyimage.com/200x100/&text=AI.jpg"></a>
</div>
</div>
</div>
Pen to play with : https://codepen.io/gc-nomade/pen/PopPNoJ
See if this helps with the images grid
.container {
display: grid;
grid: auto auto/ 1fr 1fr 1fr;
}
#media (max-width: 450px) {
.container {
grid: auto / auto;
grid-auto-flow: row;
}
}
<div class="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
</div>
}
I have made this simple example of my current grid setup:
document.querySelectorAll(".element").forEach(box =>
box.addEventListener("click", () => box.classList.toggle("compressed"))
)
.container{
display:grid;
grid-template-columns: repeat(3, min-content);
grid-template-rows:repeat(3, min-content);
grid-auto-flow:column;
gap:1rem;
}
.element{
background-color:brown;
border:1px solid black;
width:10rem;
height:10rem;
text-align:center;
color:white;
line-height:10rem;
font-size:2rem;
}
.elementBig{
grid-row-end: span 2;
height:21rem;
}
.compressed{
height:2rem;
}
<div class="container">
<div class="element elementBig">big</div>
<div class="element">1</div>
<div class="element">2</div>
<div class="element">3</div>
<div class="element">4</div>
<div class="element">5</div>
<div class="element">6</div>
<div class="element">7</div>
<div class="element">8</div>
<div class="element">9</div>
<div class="element">10</div>
</div>
when you click on a cell it's reduced but the next one does not rise up: let's say I click on "big" element, I want that "1" to rise up
in addiction i want rows and columns number to be dynamic so in the real grid i'am using this setup:
--n-colonne: 3; //per impostare massimo numero di colonne a 3 su grandi display
display: grid;
$larghezza-senza-spazi: calc(100% - (var(--n-colonne) - 1) * 1rem);
grid-template-columns: repeat(auto-fill, minmax(max(45rem, ($larghezza-senza-spazi)/var(--n-colonne)), 1fr));
grid-template-rows: repeat(12, min-content);
grid-gap: 1rem;
that will need some fix if "grid-auto-flow:column" is to be used
The problem you're facing: A grid has rows and rows have a certain height (in your case: min-content, which is 10rem as long as at least one box in the row is not compressed). In addition to that, your big box is supposed to always take up two rows as per your definition (grid-row-end: span 2;), so resizing the content of the grid-cell won't change anything.
Not sure if grid is the way to go here, there might be a solution in the new masonry addition in CSS3. Maybe give this a read: https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/
However: If you can settle on a number of cols (or calculate this somehow by using js), just place your boxes accordingly in cols and it works just fine.
document.querySelectorAll(".element").forEach(box =>
box.addEventListener("click", () => box.classList.toggle("compressed"))
)
.container {
display: grid;
grid-template-columns: repeat(3, min-content);
grid-auto-flow: column;
gap: 1em;
}
.element {
background-color: brown;
border: 1px solid black;
width: 10rem;
height: 10rem;
text-align: center;
color: white;
line-height: 10rem;
font-size: 2rem;
margin-bottom: 0.5em;
}
.elementBig {
grid-row-end: span 2;
height: 21rem;
}
.compressed {
height: 2rem;
overflow: hidden;
}
<div class="container">
<div class="col1">
<div class="element elementBig">big</div>
<div class="element">1</div>
</div>
<div class="col2">
<div class="element">2</div>
<div class="element">3</div>
<div class="element">4</div>
</div>
<div class="col3">
<div class="element">5</div>
<div class="element">6</div>
<div class="element">7</div>
</div>
<div class="col4">
<div class="element">8</div>
<div class="element">9</div>
<div class="element">10</div>
</div>
</div>
If thats not an option, you can always use flexbox, but it comes with its own challenges:
document.querySelectorAll(".element").forEach(box =>
box.addEventListener("click", () => box.classList.toggle("compressed"))
)
.container {
display: flex;
flex-flow: column wrap;
width: 100%;
max-height: 800px;
gap: 1rem;
}
.element {
background-color: brown;
border: 1px solid black;
width: 200px;
height: 200px;
text-align: center;
color: white;
line-height: 10rem;
font-size: 2rem;
}
.elementBig {
height: 21rem;
}
.compressed {
height: 2rem;
}
<div class="container">
<div class="element elementBig">big</div>
<div class="element">1</div>
<div class="element">2</div>
<div class="element">3</div>
<div class="element">4</div>
<div class="element">5</div>
<div class="element">6</div>
<div class="element">7</div>
<div class="element">8</div>
<div class="element">9</div>
<div class="element">10</div>
</div>
I tried to achieve the masonry style using css with the column layout like the markup below.
I want to know if it's possible to make the .green one to take two columns instead of one?
Thank you in advance!
.parent{
column-gap: 1rem;
column-count: 2;
}
.element{
display:inline-block;
background:red;
width:100%;
height:100px;
}
.green{
background:green;
}
<div class="parent">
<div class="element green">
</div>
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
With CSS grid you can use grid-column: span 2:
.wrapper {
display: grid;
grid-gap: 0.5rem;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-flow: dense;
padding: 0.5rem;
}
.box {
background-color: lightblue;
padding: 0.5rem;
}
.a,
.d,
.e,
.f {
background-color: lightcoral;
grid-column: span 2; /* <-- here is the trick */
}
<div class="wrapper">
<div class="box a">A</div>
<div class="box b">B</div>
<div class="box c">C</div>
<div class="box d">D</div>
<div class="box e">E</div>
<div class="box f">F</div>
<div class="box g">G</div>
<div class="box h">H</div>
</div>
Learn more about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column
Regarding masonry style: At the time of writing, Level 3 of the CSS Grid Layout specification includes a masonry value for grid-template-columns and grid-template-rows layout, though browser support is pretty non-existent: https://caniuse.com/?search=masonry
Learn about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
So instead I used grid-auto-flow: dense; on the grid, which makes grid item G come before grid item F. It's not really masonry style (placing elements in optimal position based on available vertical space), but it comes close by making the grid dense filling up all available horizontal space with the next grid item that fits that space.
"dense" packing algorithm attempts to fill in holes earlier in the grid
Learn about it here: https://developer.mozilla.org/en-US/docs/Web/CSS/grid-auto-flow
Oh, if you are new to CSS grid, I recommend watching Wes Bos' talk “CSS Grid in 45 Minutes!”: https://www.youtube.com/watch?v=DCZdCKjnBCs
CSS Grid layout provides a simple, easy and efficient solution.
.parent {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: 100px;
grid-gap: 1rem;
}
.element.green {
grid-column: 1 / -1;
background: green;
}
.element {
background: red;
}
<div class="parent">
<div class="element green"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
More information:
Make a grid column span the entire row
CSS-only masonry layout
I would say, no you can't make the single .green element take up two columns, becuase you are specifically telling the browser to use two columns. If you need it to span the two columns, then I would suggest using a separate element. Perhaps a more suitable solution for this would be to use the CSS grid layout. The snippet below contains an example of both of these solutions:
.parent {
column-gap: 1rem;
column-count: 2;
}
.element {
display: inline-block;
background: red;
width: 100%;
height: 100px;
}
.green {
background: green;
width: 100%;
height: 100px;
margin-bottom: 1rem;
}
.grid-container {
margin-top: 20px;
display: grid;
grid-template-columns: auto auto;
grid-gap: 1rem;
}
.greenGrid {
background: green;
height: 100px;
grid-column-start: 1;
grid-column-end: 3;
}
.redGrid {
background: red;
height: 100px;
}
<div class="green">
</div>
<div class="parent">
<div class="element">
</div>
<div class="element">
</div>
<div class="element">
</div>
</div>
<div class='grid-container'>
<div class='greenGrid'></div>
<div class='redGrid'></div>
<div class='redGrid'></div>
<div class='redGrid'></div>
</div>
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.
I'm trying to make a grid with items/pizza toppings to order, and I would like an "Add to cart" button under each item in the grid. How would I go about doing that?
So far I've tried simply putting a button with a line break under an element but as assumed, that didn't work.
Here is the relevant code I have in the body:
.wrapper {
width: 90%;
margin: 0 auto;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-auto-rows: 200px;
grid-row-gap: 30px;
grid-column-gap: 10px;
}
.item {
background: firebrick;
color: white;
padding: 10px;
}
.item:nth-child(even) {
background: rgb(139, 19, 19);
}
.add {
margin-bottom: 100px;
}
button {
margin-bottom: 100px;
}
#container {
background-color: maroon;
width: 1500px;
height: 1200px;
margin-left: auto;
margin-right: auto;
border-color: black;
border-width: 10px;
border-style: double;
}
<div id="container">
<div id="header">
<h1> Pizza Planet </h1>
<script src="index.js"></script>
</div>
<div id="content">
<h2>Select your items:</h2>
<div class="wrapper">
<div class="item">1</div>
<div class="add"><button>Add To Cart</button></div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
</div>
</div>
All that does is make a huge gap for another cell on the grid with a tiny add to cart button on there. Any help would be appreciated, thank you.
One approach might be to use CSS grid to achieve what you require. A simple grid layout for what you describe above could be done like this:
.item img {
width:100%;
/* Causes the button to sit below the img */
display:block;
}
.item button {
width:100%;
}
.grid {
/* Specifies css grid to be used */
display:grid;
/* Specifies the number of columns and sizes in the grid */
grid-template-columns: 1fr 1fr;
/* Specifies spacing between grid cells */
grid-gap:1rem;
}
<div class="grid">
<div class="item">
<img src="http://wallpapersdsc.net/wp-content/uploads/2015/11/Pizza_Images12.jpg" />
<button>Order</button>
</div>
<div class="item">
<img src="http://wallpapersdsc.net/wp-content/uploads/2015/11/Pizza_Images12.jpg" />
<button>Order</button>
</div>
<div class="item">
<img src="http://wallpapersdsc.net/wp-content/uploads/2015/11/Pizza_Images12.jpg" />
<button>Order</button>
</div>
<div class="item">
<img src="http://wallpapersdsc.net/wp-content/uploads/2015/11/Pizza_Images12.jpg" />
<button>Order</button>
</div>
</div>