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>
Related
Does anyone know how to set multiple divs side-by-side that are centered and have at least 10 pixels gap between each other? I managed to do it but the following divs went right under the first 2.
Here is an example of what outcome I am expecting: https://imgur.com/a/p1ilgCu
And here is the outcome I made: https://imgur.com/a/JI0beTk
.container {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 50px;
height: 50%;
width: 33.33%;
text-align: center;
transform: translate(50px, 20px);
}
.column1 {
background-color: whitesmoke;
margin-top: 10px;
border-radius: 20px;
}
<div class="container">
<div class="column1">
<img src="profilepiclink256x" style="width:50%">
<h1>text name</h1>
</div>
<div class="column1">
<img src="profilepiclink256x" style="width:50%">
<h1>text name</h1>
</div>
<div class="column1">
</div>
<div class="column1">
</div>
</div>
You can use flex to place them side by side. If you want them to fill the width of your parent element, use min-width on the children calculate 100% by the amount of divs and subtract the column gap. min-width: calc(100% / var(--num-cols) - var(--col-gap)); i used css variables.
:root {
--num-cols: 4;
--col-gap: 10px;
}
.container {
display: flex;
/* centers content when flex axis is set as row */
justify-content: center;
}
.column1 {
background-color: whitesmoke;
margin-top: 10px;
border-radius: 20px;
/* will fill parents width with children including gap
/* can also use flex-grow: 1; to fill parents width with children */
/* min-width: calc(100% / var(--num-cols) - var(--col-gap)); */
flex-grow: 1; /* remove if you do not want to spread entire width of parent width */
}
.column1~.column1 {
/* adds a gap of 10px to all but first col element */
margin-left: var(--col-gap);
}
<div class="container">
<div class="column1">
<img src="profilepiclink256x" style="width:50%">
<h1>text name</h1>
</div>
<div class="column1">
<img src="profilepiclink256x" style="width:50%">
<h1>text name</h1>
</div>
<div class="column1">
<img src="profilepiclink256x" style="width:50%">
<h1>text name</h1>
</div>
<div class="column1">
<img src="profilepiclink256x" style="width:50%">
<h1>text name</h1>
</div>
</div>
Use flex element in your css:
.container {
display: flex;
}
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 would like to display the content of these two columns only inside the container and the columns take the full width of the page like this image down bellow.
Is this possible by using css grid?
Thank you for your help and your support.
<div class="columns">
<div class="columns--container">
<div class="column">
<!-- Content -->
</div>
<div class="column">
<!-- Content -->
</div>
</div>
</div>
Ok, I'm new to grids, but this should work:
.columns {
height: 400px;
background: whitesmoke;
display: grid;
grid-template-columns: auto auto auto auto;
grid-gap: 10px;
}
.columns-container {
grid-column-start: 2;
grid-column-end: 4;
display: inherit;
grid-template-columns: auto auto;
flex-direction: row;
}
.column {
background: green;
}
<div class="columns">
<div class="columns-container">
<div class="column">
<!-- Content -->
</div>
<div class="column">
<!-- Content -->
</div>
</div>
</div>
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>
The code below shows the intended behavior when I resize the window in
Chrome 60, and in Firefox 55 (but not in iOS Safari 10.3; that is most likely another question why it misbehaves in Safari).
html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
background-color: lightgrey;
}
.container {
box-sizing: border-box;
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: repeat(3, calc((60vh - 12px)/3));
/*grid-template-rows: 1fr 1fr 1fr;*/
/*grid-template-rows: auto auto auto;*/
height: 60vh;
border: 3px solid yellow;
padding: 3px;
/*grid-gap: 20px;*/ /* <-- would also mess things up */
}
.tile {
}
img {
box-sizing: border-box;
display: block;
object-fit: contain;
width: 100%;
height: 100%;
margin: 0;
border: 0;
padding: 3px;
}
<!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
<div class="container">
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
</div>
It is important that the aspect ratio of the images (2:1)
is preserved. I would have expected either:
grid-template-rows: 1fr 1fr 1fr;
or:
grid-template-rows: auto auto auto;
makes the images fit within the rows of the grid, but neither of them does.
With:
grid-template-rows: repeat(3, calc((60vh - 12px)/3));
I get the desired behavior. How can I avoid working out the math myself? In other words, what should I do so that grid-template-rows: 1fr 1fr 1fr; (or something similar) works?
It is already difficult to work out the height of the container element in CSS on the real page. The goal is to solve it with CSS grid layout; no JavaScript, and no background image hacks.
Update: I originally excluded the background image hack for two reasons.
I thought (due to some misunderstandings) that the background image
url must be in the CSS file, but this is not the case: I can use
inline styles and have it in the HTML.
It felt hackish. After having seen how complicated and messy it gets
with nested flex containers nested inside a grid container just to make it work on Safari, I simply resorted to the background image hack as it is significantly cleaner and works in all browsers tested (Chrome, Firefox, Safari).
In the end, it is not the accepted answer that helped to solve my problem.
You can use grid-template-rows: 1fr 1fr 1fr and more importantly you have to reset the min-width and min-height values of the grid items which defaults to auto (as much as the content).
To provide a more reasonable default minimum size for grid items, this
specification defines that the auto value of min-width/min-height also
applies an automatic minimum size in the specified axis to grid items
whose overflow is visible and which span at least one track whose min
track sizing function is auto. (The effect is analogous to the
automatic minimum size imposed on flex items.)
Source: W3C
This is similar to the auto flex item rule with flexboxes. See demo below where I reset them to zero:
html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
background-color: lightgrey;
}
.container {
box-sizing: border-box;
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
height: 60vh;
border: 3px solid yellow;
padding: 3px;
/*grid-gap: 20px;*/ /* <-- would also mess things up */
}
.tile {
min-width: 0;
min-height: 0;
}
img {
box-sizing: border-box;
display: block;
object-fit: contain;
width: 100%;
height: 100%;
margin: 0;
border: 0;
padding: 3px;
}
<!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
<div class="container">
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
</div>
You have the images set to height: 100%. But 100% of what? 100% of the container? 100% of the viewport? 100% of the row? If so, what's the height of the row?
Chrome and Firefox make an educated guess about your intentions. They have implemented algorithms designed to go beyond spec guidance in order to improve user experience. They call these modifications "interventions".
Safari doesn't do this. Safari adheres strictly to spec language, which states that a percentage height on an element must have a defined height on the parent, otherwise it is ignored.
These browser differences are explained in more detail here:
CSS Grid Row Height Safari Bug
Chrome / Safari not filling 100% height of flex parent
Then you have to consider that grid items, by default, cannot be smaller than their content. If your rows are set to 1fr, but the images are taller than the space allotted, the rows must expand. You can override this behavior with min-height: 0 / min-width: 0 or overflow with any value other than visible.
This behavior is explained in more detail here:
Prevent grid items from stretching in CSS Grid Layout
Why doesn't flex item shrink past content size?
Still, once you factor in the guidance above, you can probably get your layout to work in Safari with a combination of grid and flex properties:
* {
box-sizing: border-box;
}
body {
display: flex;
flex-direction: column;
height: 100vh;
margin: 0;
background-color: lightgrey;
}
header,
footer {
flex: 0 0 100px;
background-color: tomato;
display: flex;
align-items: center;
justify-content: center;
}
.container {
flex: 1;
min-height: 0;
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-rows: auto;
padding: 3px;
}
.tile {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 0;
}
img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
padding: 3px;
}
<header>HEADER</header>
<!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
<div class="container">
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
</div>
<footer>FOOTER</footer>
jsFiddle
I don't know how snugly you want the images to fit, but you could use minmax(). minmax() lets you set a minimum and maximum value for the grid-row size. Setting auto for the min and 33% for the max will let them get as small as the content needs to get, and up to 33% of the height of the grid container, but no bigger. This will keep all your grid items together at maximum height of 99% of the 60vh that the grid container takes up.
This is not exactly the automatic way you were hoping to get... you're still declaring a size, even if it's relative. It does avoid the clunky-looking calc((60vh - 12px) / 3), though there's nothing really wrong with using that method, unless there are other constraints in your post.
However, kukkuz' answer and resetting the min-height is a better solution and is what I was missing.
html, body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: 0;
background-color: lightgrey;
}
.container {
box-sizing: border-box;
width: 100%;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: repeat(3, minmax(auto, 33%));
height: 60vh;
border: 3px solid yellow;
padding: 3px;
}
.tile {
display: grid;
}
img {
box-sizing: border-box;
display: block;
object-fit: contain;
width: 100%;
height: 100%;
margin: 0;
border: 0;
padding: 3px;
}
<!-- The image is 200 x 100 px: a green and a blue square next to each other. -->
<div class="container">
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
<div class="tile">
<img src="https://i.stack.imgur.com/qbpIG.png" alt="." />
</div>
</div>