complex grid layout which collapse into a single column on small screen - html

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>
}

Related

Multiple equal row height in CSS Grid Layout [duplicate]

This question already has answers here:
Align child elements of different blocks
(3 answers)
Closed 2 years ago.
How can I make all footers (with green background) same height, keeping content height also the same, too?
Current output:
Desired output:
CodePen: https://codepen.io/yasincad/pen/poNPgYv
Current HTML:
<div class="cards">
<div class="card">
<div>Long...<br><br><br>content</div>
<div class="card-footer">
<h3>Footer title</h3>
<div>Long...<br><br>footer text</div>
</div>
</div>
<div class="card">
<div>Shorter content</div>
<div class="card-footer">
<h3>Footer title</h3>
<div>Short footer text</div>
</div>
</div>
</div>
Current CSS:
.cards {
width: 600px;
column-gap: 30px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.card {
background-color: lightgrey;
display: grid;
grid-template-rows: 1fr auto auto;
}
.card-footer {
background: lightgreen;
}
.cards {
width: 83vw;
column-gap: 3vw;
display: flex;
}
.card {
background-color: lightgrey;
width:40vw;
}
.card-footer {
background: lightgreen;
width:40vw;
}
<div class="cards">
<div class="card">
<div>Long...<br><br><br>content</div>
</div>
<div class="card">
<div>Shorter content</div>
</div>
</div>
<div class='cards'>
<div class="card-footer">
<h3>Footer title</h3>
<div>Long...<br><br>footer text</div>
</div>
<div class="card-footer">
<h3>Footer title</h3>
<div>Short footer text</div>
</div>
</div>

Create a grid for memory game

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>

Is it possible to put buttons under each element in a grid?

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>

css - using grid-auto-column to create dynamic widths

I'm trying to get my css grid to either be 2 blocks per row (if there are enough items) or a single block that spans the entire width. However, I can't seem to get it to work using grid-auto-column.
The top block is what I want it to look like, and the bottom block is what my current css is creating.
.flex1 {
display: flex;
flex-direction: row;
flex: 1;
}
.grid1 {
display: grid;
grid-auto-columns: minmax(50%, 100%);
}
div.height {
height: 50px;
width: 100%;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
<div class="flex1">
<div class="red height">
</div>
<div class="blue height">
</div>
</div>
<div>
<div class="green height">
</div>
</div>
<br><br>
<div class="grid">
<div class="red height">
</div>
<div class="blue height">
</div>
<div class="green height">
</div>
</div>
Unfortunately, as far as I know, this isn't possible with the Grid, but it's a perfect and easy job for Flexbox, since you only need to handle one or single dimensional layout, in your case rows.
Below I'm giving you the shorter version of the desired result / behavior of flex-items, with less markup and styling:
.flex {
display: flex;
flex-wrap: wrap; /* enables wrapping of flex-items */
}
.flex > div {
flex: 1 0 50%; /* grows full width if alone in a row / doesn't shrink / initial width set to 50%, i.e. can't be less than 50% of the parent's width */
height: 50px;
}
.red {background: red}
.blue {background: blue}
.green {background: green}
.yellow {background: yellow}
<div class="flex">
<div class="red"></div>
</div>
<br>
<div class="flex">
<div class="red"></div>
<div class="blue"></div>
</div>
<br>
<div class="flex">
<div class="red"></div>
<div class="blue"></div>
<div class="green"></div>
</div>
<br>
<div class="flex">
<div class="red"></div>
<div class="blue"></div>
<div class="green"></div>
<div class="yellow"></div>
</div>
Use grid-template-areas: "a b" "c c";(change .grid1 to .grid as in html)
Also set grid-area:; to each div inside .grid
.flex1 {
display: flex;
flex-direction: row;
flex: 1;
}
.grid {
display: grid;
grid-auto-columns: minmax(50%, 100%);
grid-template-areas: "a b" "c c";
}
div.height {
height: 50px;
width: 100%;
}
.red {
background-color: red;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
<div class="flex1">
<div class="red height">
</div>
<div class="blue height">
</div>
</div>
<div>
<div class="green height">
</div>
</div>
<br><br>
<div class="grid">
<div class="red height" style="grid-area: a;">
</div>
<div class="blue height" style="grid-area: b;">
</div>
<div class="green height" style="grid-area: c;">
</div>
</div>

How can a last implicit row have a different height?

Working on a CSS Grid example that contains several photo cards (items). Let's imagine that these items are created dynamically by any server-side logic.
The last item in the grid container is a div element defined as a footer for that grid, which also contains a button that has to be center-aligned inside its parent.
By the grid definition, the footer takes the height of the implicit row: 200px. The footer element spans the 2 columns of the grid.
How can the footer, being in the last implicit row, have a smaller size than the grid-auto-rows property, defined on the grid container?
.travel-photos {
margin: 0 auto;
width: 80%;
background: lightblue;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 50px;
grid-auto-rows: 200px;
grid-gap: 20px 10px;
}
.travel-photos h1 {
text-align: center;
grid-column: 1 / 3;
}
.photo-card>img {
width: 100%;
height: 100%;
background-color: cyan;
}
.photos-footer {
background-color: lightgreen;
grid-column: 1 / 3;
}
<section class="travel-photos">
<h1>PHOTOS</h1>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photos-footer">
<button>MORE</button>
</div>
</section>
The grid-auto-rows property only accepts track sizes as values. It does not accept any form of syntax that would allow you to target a particular row.
Therefore, another method is needed to size the grid item appearing in the last implicit row.
Here's a simple solution: Target the last item directly.
.photos-footer {
height: 50px;
}
And then, because you want the content of that item (the button) centered, use flexbox:
.photos-footer {
height: 50px;
display: flex;
justify-content: center;
align-items: center;
}
Here's the full code:
.travel-photos {
margin: 0 auto;
width: 80%;
background: lightblue;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 50px;
grid-auto-rows: 200px;
grid-gap: 20px 10px;
}
.travel-photos h1 {
text-align: center;
grid-column: 1 / 3;
}
.photo-card > img {
width: 100%;
height: 100%;
background-color: cyan;
}
.photos-footer {
height: 50px;
align-self: end; /* align item to bottom of row */
display: flex;
justify-content: center;
align-items: center;
grid-column: 1 / 3;
background-color: lightgreen;
}
<section class="travel-photos">
<h1>PHOTOS</h1>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photos-footer">
<button>MORE</button>
</div>
</section>
NOTE that this solution doesn't actually change the height of the last grid row, which remains at 200px, per the grid-auto-rows rule. This solution changes only the height of the grid item inside the last row. That's why there's a gap between the penultimate row and the grid item pinned to the bottom of the last row.
If the last row itself must have a different height, then I would suggest removing it from the grid container and placing it underneath as a new element.
NOTE also that the problem raised in the question applies only in the implicit grid. In the explicit grid, defining the height of the last row (or any row, for that matter) is simple and easy.
Maybe using grid-auto-rows: min-content; is fine here . grid-template-rows:50px; will only set first row's height.
height or max-height could be used on .photo-card if necessary.
.travel-photos {
margin: 0 auto;
width: 80%;
background: lightblue;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 50px;
grid-auto-rows: min-content;
grid-gap: 20px 10px;
}
.travel-photos h1 {
text-align: center;
grid-column: 1 / 3;
}
.photo-card>img {
width: 100%;
height: 100%;
background-color: cyan;
}
.photos-footer {
background-color: lightgreen;
grid-column: 1 / 3;
}
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css">
</head>
<body>
<section class="travel-photos">
<h1>PHOTOS</h1>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photo-card">
<img src="http://lorempixel.com/200/200/">
</div>
<div class="photos-footer">
<button>MORE</button>
</div>
</section>
</body>
</html>