Stylish Image Gallery with CSS Grid and Hover Effects
Create a responsive image gallery using CSS Grid with hover effects for images.
Code
<!--
Stylish Image Gallery with CSS Grid + hover effects.
Drop this into any page; replace image URLs and captions as needed.
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Stylish Image Gallery</title>
<style>
:root{
--gap: 10px;
--radius: 12px;
--shadow: 0 12px 30px rgba(0,0,0,.18);
--speed: 240ms;
}
/* Gallery grid: responsive columns with consistent gaps */
.gallery{
display:grid;
grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
gap:var(--gap);
padding:var(--gap);
margin:0 auto;
max-width:1100px;
}
.gallery-item{
overflow:hidden;
position:relative;
border-radius:var(--radius);
background:#0f1115;
box-shadow:0 2px 10px rgba(0,0,0,.12);
isolation:isolate; /* ensures overlay/filters don't bleed */
}
.gallery-item img{
width:100%;
height:100%;
display:block;
aspect-ratio: 4 / 3; /* stable layout; prevents CLS */
object-fit:cover;
transform:translateZ(0); /* GPU hint for smooth transforms */
transition:transform var(--speed) ease, filter var(--speed) ease;
will-change:transform; /* performance: only for hoverable elements */
}
/* Subtle overlay + caption (optional) */
.gallery-item::after{
content:"";
position:absolute;
inset:0;
background:linear-gradient(to top, rgba(0,0,0,.45), rgba(0,0,0,0) 55%);
opacity:0;
transition:opacity var(--speed) ease;
pointer-events:none;
}
.gallery-item figcaption{
position:absolute;
left:12px;
right:12px;
bottom:10px;
color:#fff;
font:600 14px/1.2 system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
letter-spacing:.2px;
opacity:0;
transform:translateY(6px);
transition:opacity var(--speed) ease, transform var(--speed) ease;
text-shadow:0 2px 10px rgba(0,0,0,.35);
pointer-events:none;
}
.gallery-item:hover img{
transform:scale(1.08);
filter:saturate(1.05) contrast(1.05);
}
.gallery-item:hover::after,
.gallery-item:hover figcaption{
opacity:1;
}
.gallery-item:hover figcaption{
transform:translateY(0);
}
/* Accessibility: show hover effects on keyboard focus as well */
.gallery-item:focus-within img{ transform:scale(1.08); }
.gallery-item:focus-within::after,
.gallery-item:focus-within figcaption{ opacity:1; transform:translateY(0); }
/* Respect reduced motion preferences */
@media (prefers-reduced-motion: reduce){
.gallery-item img,
.gallery-item::after,
.gallery-item figcaption{ transition:none; }
}
</style>
</head>
<body>
<!-- Example usage: replace src/alt; captions are optional -->
<div class="gallery">
<figure class="gallery-item">
<img src="image1.jpg" alt="Image 1" loading="lazy" decoding="async" />
<figcaption>Image 1</figcaption>
</figure>
<figure class="gallery-item">
<img src="image2.jpg" alt="Image 2" loading="lazy" decoding="async" />
<figcaption>Image 2</figcaption>
</figure>
<figure class="gallery-item">
<img src="image3.jpg" alt="Image 3" loading="lazy" decoding="async" />
<figcaption>Image 3</figcaption>
</figure>
<figure class="gallery-item">
<img src="image4.jpg" alt="Image 4" loading="lazy" decoding="async" />
<figcaption>Image 4</figcaption>
</figure>
</div>
<script>
/**
* Optional enhancement: adds keyboard focusability to each gallery item
* without changing the required structure, improving accessibility.
*/
document.querySelectorAll('.gallery-item').forEach((item) => {
if (!item.hasAttribute('tabindex')) item.setAttribute('tabindex', '0');
});
</script>
</body>
</html>