20 CSS Image Hover Effects 05 / 20
CSS Card Slide Up Caption on Hover
A caption panel anchored at the bottom that slides up into view from below the image frame, revealing metadata and a category pill.
The code
<div class="ih-05">
<div class="ih-05__grid">
<div class="ih-05__card">
<div class="ih-05__img ih-05__img--1"><span class="ih-05__icon">🎵</span></div>
<div class="ih-05__caption">
<div class="ih-05__peek"><span class="ih-05__dot"></span>Synthwave</div>
<p class="ih-05__title">Neon Highways</p>
<p class="ih-05__meta">A 12-track journey through retro-futuristic soundscapes and pulsing basslines</p>
<span class="ih-05__pill">New Album</span>
</div>
</div>
<div class="ih-05__card">
<div class="ih-05__img ih-05__img--2"><span class="ih-05__icon">🌊</span></div>
<div class="ih-05__caption">
<div class="ih-05__peek"><span class="ih-05__dot"></span>Ambient</div>
<p class="ih-05__title">Ocean Mind</p>
<p class="ih-05__meta">Meditative binaural compositions recorded at the Faroe Islands coastline</p>
<span class="ih-05__pill">EP Release</span>
</div>
</div>
<div class="ih-05__card">
<div class="ih-05__img ih-05__img--3"><span class="ih-05__icon">🔮</span></div>
<div class="ih-05__caption">
<div class="ih-05__peek"><span class="ih-05__dot"></span>Electronic</div>
<p class="ih-05__title">Violet Frequencies</p>
<p class="ih-05__meta">Experimental club music blending modular synthesis and jazz improvisation</p>
<span class="ih-05__pill">Single</span>
</div>
</div>
</div>
</div> <div class="ih-05">
<div class="ih-05__grid">
<div class="ih-05__card">
<div class="ih-05__img ih-05__img--1"><span class="ih-05__icon">🎵</span></div>
<div class="ih-05__caption">
<div class="ih-05__peek"><span class="ih-05__dot"></span>Synthwave</div>
<p class="ih-05__title">Neon Highways</p>
<p class="ih-05__meta">A 12-track journey through retro-futuristic soundscapes and pulsing basslines</p>
<span class="ih-05__pill">New Album</span>
</div>
</div>
<div class="ih-05__card">
<div class="ih-05__img ih-05__img--2"><span class="ih-05__icon">🌊</span></div>
<div class="ih-05__caption">
<div class="ih-05__peek"><span class="ih-05__dot"></span>Ambient</div>
<p class="ih-05__title">Ocean Mind</p>
<p class="ih-05__meta">Meditative binaural compositions recorded at the Faroe Islands coastline</p>
<span class="ih-05__pill">EP Release</span>
</div>
</div>
<div class="ih-05__card">
<div class="ih-05__img ih-05__img--3"><span class="ih-05__icon">🔮</span></div>
<div class="ih-05__caption">
<div class="ih-05__peek"><span class="ih-05__dot"></span>Electronic</div>
<p class="ih-05__title">Violet Frequencies</p>
<p class="ih-05__meta">Experimental club music blending modular synthesis and jazz improvisation</p>
<span class="ih-05__pill">Single</span>
</div>
</div>
</div>
</div>.ih-05,.ih-05 *,.ih-05 *::before,.ih-05 *::after{margin:0;padding:0;box-sizing:border-box}
.ih-05 ::selection{background:#f472b6;color:#000}
.ih-05{
--accent:#f472b6;--accent2:#818cf8;--bg:#0a0a10;--card:#141420;--text:#f1f5f9;--muted:#64748b;
--duration:0.4s;--ease:cubic-bezier(0.16,1,0.3,1);
font-family:system-ui,sans-serif;background:var(--bg);padding:40px 24px;
min-height: 100vh;display:flex;align-items:center;justify-content:center;
}
.ih-05__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;max-width:780px;width:100%}
.ih-05__card{
position:relative;border-radius:12px;overflow:hidden;aspect-ratio:4/5;cursor:pointer;
background:var(--card);border:1px solid rgba(255,255,255,0.05);
}
.ih-05__img{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;transition:transform var(--duration) var(--ease)}
.ih-05__img--1{background:linear-gradient(150deg,#0d0d1a 0%,#1e1b4b 60%,#312e81 100%)}
.ih-05__img--2{background:linear-gradient(150deg,#042f2e 0%,#0f766e 60%,#2dd4bf 100%)}
.ih-05__img--3{background:linear-gradient(150deg,#1a0626 0%,#6b21a8 60%,#c084fc 100%)}
.ih-05__card:hover .ih-05__img{transform:scale(1.06) translateY(-4px)}
.ih-05__icon{font-size:56px;opacity:0.35;transition:opacity var(--duration) var(--ease)}
.ih-05__card:hover .ih-05__icon{opacity:0.12}
/* The caption panel slides up from the bottom */
.ih-05__caption{
position:absolute;bottom:0;left:0;right:0;
background:linear-gradient(to top, rgba(0,0,0,0.92) 0%, rgba(0,0,0,0.7) 60%, transparent 100%);
padding:40px 16px 16px;
transform:translateY(calc(100% - 44px));
transition:transform var(--duration) var(--ease);
}
.ih-05__card:hover .ih-05__caption{transform:translateY(0)}
.ih-05__peek{
font-size:12px;font-weight:600;color:var(--text);margin-bottom:10px;
display:flex;align-items:center;gap:6px;
}
.ih-05__dot{width:6px;height:6px;border-radius:50%;background:var(--accent);flex-shrink:0}
.ih-05__title{font-size:14px;font-weight:700;color:var(--text);margin-bottom:6px}
.ih-05__meta{font-size:11px;color:var(--muted);line-height:1.5}
.ih-05__pill{
display:inline-block;margin-top:8px;padding:3px 8px;border-radius:20px;
background:rgba(244,114,182,0.15);border:1px solid rgba(244,114,182,0.3);
font-size:10px;font-weight:700;color:var(--accent);letter-spacing:0.06em;
}
@media(prefers-reduced-motion:reduce){
.ih-05__img,.ih-05__icon,.ih-05__caption{transition:none}
.ih-05__caption{transform:none}
} .ih-05,.ih-05 *,.ih-05 *::before,.ih-05 *::after{margin:0;padding:0;box-sizing:border-box}
.ih-05 ::selection{background:#f472b6;color:#000}
.ih-05{
--accent:#f472b6;--accent2:#818cf8;--bg:#0a0a10;--card:#141420;--text:#f1f5f9;--muted:#64748b;
--duration:0.4s;--ease:cubic-bezier(0.16,1,0.3,1);
font-family:system-ui,sans-serif;background:var(--bg);padding:40px 24px;
min-height: 100vh;display:flex;align-items:center;justify-content:center;
}
.ih-05__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;max-width:780px;width:100%}
.ih-05__card{
position:relative;border-radius:12px;overflow:hidden;aspect-ratio:4/5;cursor:pointer;
background:var(--card);border:1px solid rgba(255,255,255,0.05);
}
.ih-05__img{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;transition:transform var(--duration) var(--ease)}
.ih-05__img--1{background:linear-gradient(150deg,#0d0d1a 0%,#1e1b4b 60%,#312e81 100%)}
.ih-05__img--2{background:linear-gradient(150deg,#042f2e 0%,#0f766e 60%,#2dd4bf 100%)}
.ih-05__img--3{background:linear-gradient(150deg,#1a0626 0%,#6b21a8 60%,#c084fc 100%)}
.ih-05__card:hover .ih-05__img{transform:scale(1.06) translateY(-4px)}
.ih-05__icon{font-size:56px;opacity:0.35;transition:opacity var(--duration) var(--ease)}
.ih-05__card:hover .ih-05__icon{opacity:0.12}
/* The caption panel slides up from the bottom */
.ih-05__caption{
position:absolute;bottom:0;left:0;right:0;
background:linear-gradient(to top, rgba(0,0,0,0.92) 0%, rgba(0,0,0,0.7) 60%, transparent 100%);
padding:40px 16px 16px;
transform:translateY(calc(100% - 44px));
transition:transform var(--duration) var(--ease);
}
.ih-05__card:hover .ih-05__caption{transform:translateY(0)}
.ih-05__peek{
font-size:12px;font-weight:600;color:var(--text);margin-bottom:10px;
display:flex;align-items:center;gap:6px;
}
.ih-05__dot{width:6px;height:6px;border-radius:50%;background:var(--accent);flex-shrink:0}
.ih-05__title{font-size:14px;font-weight:700;color:var(--text);margin-bottom:6px}
.ih-05__meta{font-size:11px;color:var(--muted);line-height:1.5}
.ih-05__pill{
display:inline-block;margin-top:8px;padding:3px 8px;border-radius:20px;
background:rgba(244,114,182,0.15);border:1px solid rgba(244,114,182,0.3);
font-size:10px;font-weight:700;color:var(--accent);letter-spacing:0.06em;
}
@media(prefers-reduced-motion:reduce){
.ih-05__img,.ih-05__icon,.ih-05__caption{transition:none}
.ih-05__caption{transform:none}
}How this works
The caption wrapper uses position: absolute; bottom: 0 and begins with transform: translateY(calc(100% - 44px)) — this value ensures the top "peek" strip (containing the dot and category name) remains visible as a persistent visual hint. On hover, transform: translateY(0) slides the whole panel fully into view.
The calc() expression ties the resting offset to the height of the peek strip, so if that strip height changes (e.g. larger font), the math remains correct. A linear gradient on the caption background provides the smooth transition from solid to transparent so it never appears as a hard edge over the image.
Customize
- Tune the peek height by changing
44pxin thetranslateYcalc — the value should equal the height of the always-visible strip. - Replace the gradient background with
backdrop-filter: blur()for a glassmorphic caption panel on top of busy imagery. - Add a subtle
scale(1.03)to the image on hover to visually separate it from the rising panel. - For horizontal caption reveal, switch to
transform: translateX()and anchor the panel to the left or right edge instead of bottom. - Include a "tap to reveal" ARIA label (
aria-label="Show details") on the card for keyboard and screen reader users.
Watch out for
- The
calc(100% - 44px)technique relies on the caption being the same height at rest as when expanded — if content is dynamic, usemax-heighttransitions instead but note the easing will be linear. - Setting
overflow: hiddenon the card clips the sliding panel; ensure the card wrapper does not restrict the panel's travel path. - iOS Safari below 15.4 has a known bug where
transformon absolutely-positioned children inside an overflow:hidden parent flickers — adding-webkit-overflow-scrolling: touchon the card often resolves it.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 51+ | 9+ | 36+ | 51+ |
Uses only CSS transforms, opacity, and linear-gradient — all broadly supported with no prefixes required.