This fun “bento box” style gallery is made in pure CSS, made possible by the new :has()
selector!
See the Pen Untitled by Addy (@addy-codes) on CodePen.
When I first tried to build this out, I was set on a CSS grid based solution. However, there didn’t seem to be an effective way to dynamically break the images out or adjust it on the fly to give the desired hover expand effect.
In the end I settled on more absolute positioning, but using percentage widths it is still perfectly responsive. If you have a smarter solution I’d love to know in the comments! 😄
Grab the code
<div class="image-grid">
<div class="image-wrapper image-1">
<img src="https://placecats.com/800/600/" alt="Image 1">
</div>
<div class="image-wrapper image-2">
<img src="https://placecats.com/800/700/" alt="Image 2">
</div>
<div class="image-wrapper image-3">
<img src="https://placecats.com/1000/600/" alt="Image 3">
</div>
<div class="image-wrapper image-4">
<img src="https://placecats.com/900/600/" alt="Image 4">
</div>
<div class="image-wrapper image-5">
<img src="https://placecats.com/800/500/" alt="Image 5">
</div>
</div>
.image-grid {
margin: 0 auto;
position: relative;
width: 100%;
aspect-ratio: 3 / 2;
background: #fff;
overflow: hidden;
.image-wrapper {
position: absolute;
border-radius: 0.5rem;
overflow: hidden;
transition: all 0.4s ease;
z-index: 1;
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 0.5rem;
transition: all 0.4s ease;
}
}
.image-1 { left: 0%; top: 0%; width: 31.5%; height: 30.5%; }
.image-2 { left: 0%; top: 34.5%; width: 31.5%; height: 65%; }
.image-3 { left: calc(31.5% + 2.7%); top: 0%; width: 31.5%; height: 100%; }
.image-4 { left: calc(31.5% + 2.7% + 31.5% + 2.7%); top: 0%; width: 31.5%; height: 65%; }
.image-5 { left: 68.4%; top: 69%; width: 31.5%; height: 30.5%; }
&:has(.image-wrapper:hover) {
.image-wrapper {
transform: scale(0.1);
opacity: 0.3;
pointer-events: none;
&:hover {
transform: none;
opacity: 1;
pointer-events: auto;
z-index: 10;
left: 0; top: 0; width: 100%; height: 100%;
}
}
}
}