20 CSS Image Hover Effects 15 / 20
CSS Image Ripple Animation Hover
Concentric circle ripples emanate outward from a circular avatar on hover, driven by staggered keyframe animations on sibling span elements.
The code
<div class="ih-15">
<div class="ih-15__grid">
<div class="ih-15__item">
<div class="ih-15__frame">
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<div class="ih-15__avatar ih-15__avatar--1">👩🚀</div>
</div>
<div style="text-align:center">
<p class="ih-15__name">Dr. Elena Vasquez</p>
<p class="ih-15__role">Mission Architect</p>
<div class="ih-15__socials">
<span class="ih-15__social">𝕏</span>
<span class="ih-15__social">in</span>
<span class="ih-15__social">gh</span>
</div>
</div>
</div>
<div class="ih-15__item">
<div class="ih-15__frame">
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<div class="ih-15__avatar ih-15__avatar--2">🧙</div>
</div>
<div style="text-align:center">
<p class="ih-15__name">Orion Blackwood</p>
<p class="ih-15__role">AI Research Lead</p>
<div class="ih-15__socials">
<span class="ih-15__social">𝕏</span>
<span class="ih-15__social">in</span>
<span class="ih-15__social">gh</span>
</div>
</div>
</div>
<div class="ih-15__item">
<div class="ih-15__frame">
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<div class="ih-15__avatar ih-15__avatar--3">👩🌾</div>
</div>
<div style="text-align:center">
<p class="ih-15__name">Freya Lindqvist</p>
<p class="ih-15__role">Growth Engineer</p>
<div class="ih-15__socials">
<span class="ih-15__social">𝕏</span>
<span class="ih-15__social">in</span>
<span class="ih-15__social">gh</span>
</div>
</div>
</div>
</div>
</div> <div class="ih-15">
<div class="ih-15__grid">
<div class="ih-15__item">
<div class="ih-15__frame">
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<div class="ih-15__avatar ih-15__avatar--1">👩🚀</div>
</div>
<div style="text-align:center">
<p class="ih-15__name">Dr. Elena Vasquez</p>
<p class="ih-15__role">Mission Architect</p>
<div class="ih-15__socials">
<span class="ih-15__social">𝕏</span>
<span class="ih-15__social">in</span>
<span class="ih-15__social">gh</span>
</div>
</div>
</div>
<div class="ih-15__item">
<div class="ih-15__frame">
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<div class="ih-15__avatar ih-15__avatar--2">🧙</div>
</div>
<div style="text-align:center">
<p class="ih-15__name">Orion Blackwood</p>
<p class="ih-15__role">AI Research Lead</p>
<div class="ih-15__socials">
<span class="ih-15__social">𝕏</span>
<span class="ih-15__social">in</span>
<span class="ih-15__social">gh</span>
</div>
</div>
</div>
<div class="ih-15__item">
<div class="ih-15__frame">
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<span class="ih-15__ring"></span>
<div class="ih-15__avatar ih-15__avatar--3">👩🌾</div>
</div>
<div style="text-align:center">
<p class="ih-15__name">Freya Lindqvist</p>
<p class="ih-15__role">Growth Engineer</p>
<div class="ih-15__socials">
<span class="ih-15__social">𝕏</span>
<span class="ih-15__social">in</span>
<span class="ih-15__social">gh</span>
</div>
</div>
</div>
</div>
</div>.ih-15,.ih-15 *,.ih-15 *::before,.ih-15 *::after{margin:0;padding:0;box-sizing:border-box}
.ih-15 ::selection{background:#2dd4bf;color:#000}
.ih-15{
--accent:#2dd4bf;--bg:#060d0d;--text:#f1f5f9;--muted:#64748b;
font-family:system-ui,sans-serif;background:var(--bg);padding:40px 24px;
min-height: 100vh;display:flex;align-items:center;justify-content:center;
}
.ih-15__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;max-width:780px;width:100%}
.ih-15__item{display:flex;flex-direction:column;align-items:center;gap:14px;cursor:pointer}
/* Ripple container — must be position:relative so pseudo rings use absolute */
.ih-15__frame{
position:relative;width:140px;height:140px;
display:flex;align-items:center;justify-content:center;
}
.ih-15__avatar{
width:100px;height:100px;border-radius:50%;
display:flex;align-items:center;justify-content:center;
font-size:42px;position:relative;z-index:2;
transition:transform 0.3s cubic-bezier(0.34,1.56,0.64,1);
}
.ih-15__avatar--1{background:radial-gradient(circle,#1e3a5f,#0369a1)}
.ih-15__avatar--2{background:radial-gradient(circle,#3b0764,#7e22ce)}
.ih-15__avatar--3{background:radial-gradient(circle,#052e16,#15803d)}
.ih-15__item:hover .ih-15__avatar{transform:scale(1.08)}
/* Three ripple rings using sibling spans — keyframe scales + fades */
.ih-15__ring{
position:absolute;border-radius:50%;
border:2px solid var(--accent);
opacity:0;
animation:none;
}
.ih-15__item:hover .ih-15__ring{
animation:ih-15-ripple 1.5s cubic-bezier(0,0.2,0.8,1) infinite;
}
.ih-15__ring:nth-child(2){animation-delay:0s}
.ih-15__ring:nth-child(3){animation-delay:0.5s}
.ih-15__ring:nth-child(4){animation-delay:1s}
@keyframes ih-15-ripple{
0%{width:100px;height:100px;opacity:0.6;top:calc(50% - 50px);left:calc(50% - 50px)}
100%{width:140px;height:140px;opacity:0;top:calc(50% - 70px);left:calc(50% - 70px)}
}
/* Colour the rings per item */
.ih-15__item:nth-child(1) .ih-15__ring{border-color:#38bdf8}
.ih-15__item:nth-child(2) .ih-15__ring{border-color:#c084fc}
.ih-15__item:nth-child(3) .ih-15__ring{border-color:#4ade80}
.ih-15__name{font-size:14px;font-weight:700;color:var(--text)}
.ih-15__role{font-size:11px;color:var(--muted)}
.ih-15__socials{display:flex;gap:8px;margin-top:4px}
.ih-15__social{width:26px;height:26px;border-radius:50%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.08);display:flex;align-items:center;justify-content:center;font-size:12px;transition:background 0.2s ease}
.ih-15__item:hover .ih-15__social{background:rgba(255,255,255,0.1)}
@media(prefers-reduced-motion:reduce){.ih-15__ring,.ih-15__avatar{animation:none!important;transition:none}} .ih-15,.ih-15 *,.ih-15 *::before,.ih-15 *::after{margin:0;padding:0;box-sizing:border-box}
.ih-15 ::selection{background:#2dd4bf;color:#000}
.ih-15{
--accent:#2dd4bf;--bg:#060d0d;--text:#f1f5f9;--muted:#64748b;
font-family:system-ui,sans-serif;background:var(--bg);padding:40px 24px;
min-height: 100vh;display:flex;align-items:center;justify-content:center;
}
.ih-15__grid{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;max-width:780px;width:100%}
.ih-15__item{display:flex;flex-direction:column;align-items:center;gap:14px;cursor:pointer}
/* Ripple container — must be position:relative so pseudo rings use absolute */
.ih-15__frame{
position:relative;width:140px;height:140px;
display:flex;align-items:center;justify-content:center;
}
.ih-15__avatar{
width:100px;height:100px;border-radius:50%;
display:flex;align-items:center;justify-content:center;
font-size:42px;position:relative;z-index:2;
transition:transform 0.3s cubic-bezier(0.34,1.56,0.64,1);
}
.ih-15__avatar--1{background:radial-gradient(circle,#1e3a5f,#0369a1)}
.ih-15__avatar--2{background:radial-gradient(circle,#3b0764,#7e22ce)}
.ih-15__avatar--3{background:radial-gradient(circle,#052e16,#15803d)}
.ih-15__item:hover .ih-15__avatar{transform:scale(1.08)}
/* Three ripple rings using sibling spans — keyframe scales + fades */
.ih-15__ring{
position:absolute;border-radius:50%;
border:2px solid var(--accent);
opacity:0;
animation:none;
}
.ih-15__item:hover .ih-15__ring{
animation:ih-15-ripple 1.5s cubic-bezier(0,0.2,0.8,1) infinite;
}
.ih-15__ring:nth-child(2){animation-delay:0s}
.ih-15__ring:nth-child(3){animation-delay:0.5s}
.ih-15__ring:nth-child(4){animation-delay:1s}
@keyframes ih-15-ripple{
0%{width:100px;height:100px;opacity:0.6;top:calc(50% - 50px);left:calc(50% - 50px)}
100%{width:140px;height:140px;opacity:0;top:calc(50% - 70px);left:calc(50% - 70px)}
}
/* Colour the rings per item */
.ih-15__item:nth-child(1) .ih-15__ring{border-color:#38bdf8}
.ih-15__item:nth-child(2) .ih-15__ring{border-color:#c084fc}
.ih-15__item:nth-child(3) .ih-15__ring{border-color:#4ade80}
.ih-15__name{font-size:14px;font-weight:700;color:var(--text)}
.ih-15__role{font-size:11px;color:var(--muted)}
.ih-15__socials{display:flex;gap:8px;margin-top:4px}
.ih-15__social{width:26px;height:26px;border-radius:50%;background:rgba(255,255,255,0.06);border:1px solid rgba(255,255,255,0.08);display:flex;align-items:center;justify-content:center;font-size:12px;transition:background 0.2s ease}
.ih-15__item:hover .ih-15__social{background:rgba(255,255,255,0.1)}
@media(prefers-reduced-motion:reduce){.ih-15__ring,.ih-15__avatar{animation:none!important;transition:none}}How this works
Three span elements are positioned absolutely at the centre of the avatar frame with border-radius: 50% and a coloured border. At rest they have opacity: 0 and no animation. On parent hover, each receives an animation: ih-15-ripple 1.5s with staggered delays (0s, 0.5s, 1s) so they fire sequentially. The keyframe expands the element from the avatar's exact diameter (100px) to the frame boundary (140px) while fading opacity from 0.6 to 0. Because width/height are animated in the keyframe (not transform), the rings expand from the true centre.
The animation: none at rest combined with the hover-added animation means the ring is completely inactive when not hovered, consuming zero compositor resources.
Customize
- Switch from
width/heightkeyframe expansion totransform: scale()with a fixed-size element for better GPU performance on pages with many avatar rings. - Increase the ring count by adding more
spans and extending the delay series:0s, 0.33s, 0.66s, 1sfor four rings. - Change the ring style from a full border to a dashed or dotted border for a technical/radar aesthetic.
- Apply the animation permanently (remove the hover condition) for notification badges or "live" status indicators on profile images.
- Use
conic-gradientinstead of a solid border for a spinning gradient ring effect alongside the ripple.
Watch out for
- Animating
widthandheightin the keyframe forces layout recalculation — usetransform: scale()on a fixed-size element in performance-critical contexts. - The animation must be set to
noneat rest and added via a:hoverselector — if it is always running (just invisible via opacity), it will consume animation thread resources even off-screen. - In Safari, an animation that references a fixed start size via a keyframe percentage and pixel values can have timing inconsistencies if the parent is resized — set explicit widths on the ring spans.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 43+ | 9+ | 16+ | 43+ |
CSS animation with keyframes is universally supported; the border-radius circle expansion technique works in all modern browsers.