I'm building a site with multiple image galleries, each with a different number of images. What I wanted to do is to set a fixed number of rows(2, in this case) and it auto generates the amount of columns so that all images fit within the grid dynamically.
I was able to achieve something similar, but it made the images display out of order, and I really wanted them to be in the order I put in the HTML file.
Here's what I was able to do:
.gallery {
display: grid;
grid-auto-flow: column;
grid-template-rows: auto auto;
grid-gap: 5px;
width: 100%;
}
.gallery img {
height: 180px;
width: 100%;
background-color: chartreuse;
}
<div class="gallery">
<img src="images/img1.png"/>
<img src="images/img2.png"/>
<img src="images/img3.png"/>
<img src="images/img4.png"/>
<img src="images/img5.png"/>
<img src="images/img6.png"/>
<img src="images/img7.png"/>
<img src="images/img8.png"/>
</div>
<div class="gallery">
<img src="images/img1.png"/>
<img src="images/img2.png"/>
<img src="images/img3.png"/>
<img src="images/img4.png"/>
<img src="images/img5.png"/>
<img src="images/img6.png"/>
</div>
The only other way I could thing of is multiple galleries (like .gallery-4cols and .gallery-3cols) but if it can be done with only one, it would be preferable. Also, I'd like to achieve this without any JavaScript. Thanks :^)
Assuming that:
if the total number of images is an even amount then each of the two rows of a .gallery
gets half of the amount. (n / 2) + (n / 2)
if the total number of images is an odd amount then the second row of a .gallery
gets one less image than the first. ((n / 2) + 1) + (n / 2)
there's a practical limit to the total amount of images in a .gallery
. 12 (although you can have more)
There's no need to hard code anything in HTML and the pattern is simple to follow. There's basically 3 simple steps:
First, add a custom property to :root
:
--qty: 1;
--qty
will be the number of columns (images) per row.
Next, a series of rulesets that progressively increase to a predetermined limit of images. The following ruleset declares the following:
"If .gallery
:has()
at least 3 children then custom property --qty
is 2"
.gallery:has(:nth-last-child(3)) {
--qty: 2;
}
Start with 3, end with (limit - 1), and increase by 2 (ex. 3, 5, 7, ...). Increase --qty
by 1.
Finally, insure that .gallery
has the these two property/values (lines):
display: grid;
grid-template-columns: repeat(var(--qty), 1fr);
I recommend that you add: max-width: 100vw;
to .gallery
as well so that no matter what the viewport is each .gallery
will span from edge to edge with no cutoff, plus each .gallery
will be very responsive.
The following example covers for 1 to 12 images per .gallery
. If any .gallery
has 13 or more images, it will create more rows to accommodate. Continue the pattern in step #2 if more than two rows is undesirable.
Note: In the example, each <img>
is wrapped in a <figure>
which is purely optional.
Update: An additional example with JavaScript was added.
/*
|| Step #1
*/
:root {
--qty: 1;
}
/*
|| Step #2
|| The next 5 rulesets
*/
.gallery:has(:nth-last-child(3)) {
--qty: 2;
}
.gallery:has(:nth-last-child(5)) {
--qty: 3;
}
.gallery:has(:nth-last-child(7)) {
--qty: 4;
}
.gallery:has(:nth-last-child(9)) {
--qty: 5;
}
.gallery:has(:nth-last-child(11)) {
--qty: 6;
}
/*
|| Step #3
|| The first two property/values (lines)
*/
.gallery {
display: grid;
grid-template-columns: repeat(var(--qty), 1fr);
gap: 0.5vw;
max-width: 100vw; /* Recommended */
margin: 1vw auto;
padding: 1vw;
background: magenta;
}
.gallery figure {
display: flex;
justify-items: center;
height: 180px;
margin: 0;
background: chartreuse;
}
figure img {
width: 100%;
/*
|| <img> isn't cutoff or distorted.
|| Change to 'cover' if you want <img> to fill
|| <figure> and get cutoff.
*/
object-fit: contain;
object-position: center;
}
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=6">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=7">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=8">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=9">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=10">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=11">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=12">
</figure>
</section>
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/lime?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=6">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=7">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=8">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=9">
</figure>
</section>
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=6">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=7">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=8">
</figure>
</section>
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=6">
</figure>
</section>
This example uses JavaScript to assign CSS property --qty
to each .gallery
, for example:
<section class="gallery" style="--qty: 5">
<!-- 10 children -->
</section>
<section class="gallery" style="--qty: 8">
<!-- 15 children -->
</section>
// Collect all .gallery into an array-like object
const galleries = document.querySelectorAll(".gallery");
// .forEach() .gallery...
galleries.forEach(gallery => {
// ...get the number of children it has...
const kids = gallery.children.length;
// ...then divide that number by 2 and round up...
const cols = Math.ceil(kids / 2);
// ...then assign that number to its --qty
gallery.style.setProperty("--qty", cols);
});
/*
|| The first two property/values (lines)
*/
.gallery {
display: grid;
grid-template-columns: repeat(var(--qty), 1fr);
gap: 0.5vw;
max-width: 100vw; /* Recommended */
margin: 1vw auto;
padding: 1vw;
background: magenta;
}
.gallery figure {
display: flex;
justify-items: center;
height: 180px;
margin: 0;
background: chartreuse;
}
figure img {
width: 100%;
/*
|| <img> isn't cutoff or distorted.
|| Change to 'cover' if you want <img> to fill
|| <figure> and get cutoff.
*/
object-fit: contain;
object-position: center;
}
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=6">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=7">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=8">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=9">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=10">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=11">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/f662d0?text=12">
</figure>
</section>
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/lime?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=6">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=7">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=8">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/lime?text=9">
</figure>
</section>
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=6">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=7">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/cyan?text=8">
</figure>
</section>
<section class="gallery">
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=1">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=2">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=3">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=4">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=5">
</figure>
<figure>
<img src="https://placehold.co/320x180/000/tomato?text=6">
</figure>
</section>