20 CSS Image Hover Effects04 / 20

Pure CSSMIT licensed

CSS Grid Image Blur Overlay Text Hover

Visually soft hover where the background image blurs under a dark overlay via backdrop-filter to make typography legible.

Published

Live Demo
Try it

The code

<div class="ih-04">
  <div class="ih-04__grid">
    <div class="ih-04__card">
      <div class="ih-04__bg ih-04__bg--1"></div>
      <span class="ih-04__emoji">🌌</span>
      <div class="ih-04__overlay">
        <p class="ih-04__cat">Editorial</p>
        <p class="ih-04__title">The Infinite Canvas</p>
        <p class="ih-04__desc">Exploring the boundaries of digital art in 2025</p>
      </div>
    </div>
    <div class="ih-04__card">
      <div class="ih-04__bg ih-04__bg--2"></div>
      <span class="ih-04__emoji">🌿</span>
      <div class="ih-04__overlay">
        <p class="ih-04__cat">Nature</p>
        <p class="ih-04__title">Bioluminescent Depths</p>
        <p class="ih-04__desc">Life thriving in the ocean's twilight zone</p>
      </div>
    </div>
    <div class="ih-04__card">
      <div class="ih-04__bg ih-04__bg--3"></div>
      <span class="ih-04__emoji">✨</span>
      <div class="ih-04__overlay">
        <p class="ih-04__cat">Culture</p>
        <p class="ih-04__title">Neon Flux Collection</p>
        <p class="ih-04__desc">Street art meets future-forward design aesthetics</p>
      </div>
    </div>
  </div>
</div>
.ih-04,
.ih-04 *,
.ih-04 *::before,
.ih-04 *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.ih-04 ::selection {
  background: #8b5cf6;
  color: #fff;
}

.ih-04 {
  --accent: #8b5cf6;
  --bg: #080810;
  --text: #f1f5f9;
  --muted: #94a3b8;
  --duration: 0.4s;
  --ease: cubic-bezier(0.25,0.46,0.45,0.94);
  font-family: system-ui,sans-serif;
  background: var(--bg);
  padding: 40px 24px;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ih-04__grid {
  display: grid;
  grid-template-columns: repeat(3,1fr);
  gap: 16px;
  max-width: 780px;
  width: 100%;
}

.ih-04__card {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  aspect-ratio: 3/4;
  cursor: pointer;
}

.ih-04__bg {
  position: absolute;
  inset: 0;
  transition: filter var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.ih-04__bg--1 {
  background: linear-gradient(135deg,#0f0c29,#302b63,#24243e);
}

.ih-04__bg--2 {
  background: linear-gradient(135deg,#0a3d2e,#155e43,#6ee7b7);
}

.ih-04__bg--3 {
  background: linear-gradient(135deg,#1a0010,#6b1d4e,#e879f9);
}

.ih-04__emoji {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-60%);
  font-size: 60px;
  opacity: 0.35;
  transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease);
}
/* backdrop-filter blur on overlay — applied to the ::before pseudo so it blurs the sibling bg */

.ih-04__overlay {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0);
  /* We use backdrop-filter on the overlay itself */
  backdrop-filter: blur(0px) brightness(1);
  -webkit-backdrop-filter: blur(0px) brightness(1);
  transition: backdrop-filter var(--duration) var(--ease), -webkit-backdrop-filter var(--duration) var(--ease), background var(--duration) var(--ease);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 20px;
}

.ih-04__card:hover .ih-04__bg {
  transform: scale(1.05);
}

.ih-04__card:hover .ih-04__emoji {
  opacity: 0.08;
  transform: translate(-50%,-60%) scale(1.2);
}

.ih-04__card:hover .ih-04__overlay {
  backdrop-filter: blur(8px) brightness(0.6);
  -webkit-backdrop-filter: blur(8px) brightness(0.6);
  background: rgba(0,0,0,0.15);
}

.ih-04__cat {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 6px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.ih-04__title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity calc(var(--duration)*1.1) var(--ease), transform calc(var(--duration)*1.1) var(--ease);
}

.ih-04__desc {
  font-size: 11px;
  color: var(--muted);
  margin-top: 5px;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity calc(var(--duration)*1.2) var(--ease), transform calc(var(--duration)*1.2) var(--ease);
}

.ih-04__card:hover .ih-04__cat,
.ih-04__card:hover .ih-04__title,
.ih-04__card:hover .ih-04__desc {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .ih-04__bg,
    .ih-04__overlay,
    .ih-04__cat,
    .ih-04__title,
    .ih-04__desc,
    .ih-04__emoji {
    transition: none;
  }

  .ih-04__overlay {
    backdrop-filter: blur(8px) brightness(0.6);
  }

  .ih-04__cat,
    .ih-04__title,
    .ih-04__desc {
    opacity: 1;
    transform: none;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Image Hover Effect from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: CSS Grid Image Blur Overlay Text Hover
Source: https://codefronts.com/motion/css-image-hover-effects/css-grid-image-blur-overlay-text-hover/

Visually soft hover where the background image blurs under a dark overlay via backdrop-filter to make typography legible.
## HTML
```html
<div class="ih-04">
  <div class="ih-04__grid">
    <div class="ih-04__card">
      <div class="ih-04__bg ih-04__bg--1"></div>
      <span class="ih-04__emoji">🌌</span>
      <div class="ih-04__overlay">
        <p class="ih-04__cat">Editorial</p>
        <p class="ih-04__title">The Infinite Canvas</p>
        <p class="ih-04__desc">Exploring the boundaries of digital art in 2025</p>
      </div>
    </div>
    <div class="ih-04__card">
      <div class="ih-04__bg ih-04__bg--2"></div>
      <span class="ih-04__emoji">🌿</span>
      <div class="ih-04__overlay">
        <p class="ih-04__cat">Nature</p>
        <p class="ih-04__title">Bioluminescent Depths</p>
        <p class="ih-04__desc">Life thriving in the ocean's twilight zone</p>
      </div>
    </div>
    <div class="ih-04__card">
      <div class="ih-04__bg ih-04__bg--3"></div>
      <span class="ih-04__emoji">✨</span>
      <div class="ih-04__overlay">
        <p class="ih-04__cat">Culture</p>
        <p class="ih-04__title">Neon Flux Collection</p>
        <p class="ih-04__desc">Street art meets future-forward design aesthetics</p>
      </div>
    </div>
  </div>
</div>
```
## CSS
```css
.ih-04,
.ih-04 *,
.ih-04 *::before,
.ih-04 *::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.ih-04 ::selection {
  background: #8b5cf6;
  color: #fff;
}

.ih-04 {
  --accent: #8b5cf6;
  --bg: #080810;
  --text: #f1f5f9;
  --muted: #94a3b8;
  --duration: 0.4s;
  --ease: cubic-bezier(0.25,0.46,0.45,0.94);
  font-family: system-ui,sans-serif;
  background: var(--bg);
  padding: 40px 24px;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ih-04__grid {
  display: grid;
  grid-template-columns: repeat(3,1fr);
  gap: 16px;
  max-width: 780px;
  width: 100%;
}

.ih-04__card {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  aspect-ratio: 3/4;
  cursor: pointer;
}

.ih-04__bg {
  position: absolute;
  inset: 0;
  transition: filter var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.ih-04__bg--1 {
  background: linear-gradient(135deg,#0f0c29,#302b63,#24243e);
}

.ih-04__bg--2 {
  background: linear-gradient(135deg,#0a3d2e,#155e43,#6ee7b7);
}

.ih-04__bg--3 {
  background: linear-gradient(135deg,#1a0010,#6b1d4e,#e879f9);
}

.ih-04__emoji {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-60%);
  font-size: 60px;
  opacity: 0.35;
  transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease);
}
/* backdrop-filter blur on overlay — applied to the ::before pseudo so it blurs the sibling bg */

.ih-04__overlay {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0);
  /* We use backdrop-filter on the overlay itself */
  backdrop-filter: blur(0px) brightness(1);
  -webkit-backdrop-filter: blur(0px) brightness(1);
  transition: backdrop-filter var(--duration) var(--ease), -webkit-backdrop-filter var(--duration) var(--ease), background var(--duration) var(--ease);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 20px;
}

.ih-04__card:hover .ih-04__bg {
  transform: scale(1.05);
}

.ih-04__card:hover .ih-04__emoji {
  opacity: 0.08;
  transform: translate(-50%,-60%) scale(1.2);
}

.ih-04__card:hover .ih-04__overlay {
  backdrop-filter: blur(8px) brightness(0.6);
  -webkit-backdrop-filter: blur(8px) brightness(0.6);
  background: rgba(0,0,0,0.15);
}

.ih-04__cat {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 6px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity var(--duration) var(--ease), transform var(--duration) var(--ease);
}

.ih-04__title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
  opacity: 0;
  transform: translateY(12px);
  transition: opacity calc(var(--duration)*1.1) var(--ease), transform calc(var(--duration)*1.1) var(--ease);
}

.ih-04__desc {
  font-size: 11px;
  color: var(--muted);
  margin-top: 5px;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity calc(var(--duration)*1.2) var(--ease), transform calc(var(--duration)*1.2) var(--ease);
}

.ih-04__card:hover .ih-04__cat,
.ih-04__card:hover .ih-04__title,
.ih-04__card:hover .ih-04__desc {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .ih-04__bg,
    .ih-04__overlay,
    .ih-04__cat,
    .ih-04__title,
    .ih-04__desc,
    .ih-04__emoji {
    transition: none;
  }

  .ih-04__overlay {
    backdrop-filter: blur(8px) brightness(0.6);
  }

  .ih-04__cat,
    .ih-04__title,
    .ih-04__desc {
    opacity: 1;
    transform: none;
  }
}
```

How this works

backdrop-filter: blur(8px) brightness(0.6) is applied to the overlay element rather than the image itself. This means the blur composites against everything rendered behind the overlay — the image, any gradients, any decorative shapes. On hover, both the blur and brightness values animate from zero using a transition on the backdrop-filter shorthand.

Text children of the overlay start hidden with opacity: 0; transform: translateY(10px) and enter on hover, staggered via duration multipliers. The image simultaneously scales up slightly with transform: scale(1.05) to reinforce that it is "active", while the blur softens it visually to push it to the background.

Make it yours

  • Increase the blur radius to blur(16px) for a more opaque frosted-glass feel, or drop it to blur(4px) for a subtle soft-focus effect.
  • Tint the overlay with a brand colour: background: rgba(124, 58, 237, 0.15) gives a violet wash while still showing the image beneath.
  • Add saturate(0.5) to the backdrop-filter stack to desaturate the image as it blurs: backdrop-filter: blur(8px) brightness(0.6) saturate(0.5).
  • For cards with bright images, increase the brightness reduction: brightness(0.45) ensures white text remains AA contrast-compliant.
  • Combine with a mix-blend-mode: multiply on the overlay background for more aggressive colour grading effects.

Gotchas — read before shipping

  • backdrop-filter does NOT work on elements that are siblings of the blurred content — it only blurs what is visually behind it in the stacking order. The overlay must be a child or sibling sitting on top of the image layer.
  • Safari requires the -webkit-backdrop-filter vendor prefix in addition to the unprefixed version — always include both.
  • Animating backdrop-filter can cause significant GPU memory usage when many cards are visible simultaneously — consider applying only within a visible viewport via IntersectionObserver.

Browser support

ChromeSafariFirefoxEdge
76+9+ (prefixed)103+76+

Firefox added backdrop-filter support in v103 without a flag; older Firefox versions will see the text overlay without blur.

Techniques used in this demo

Search CodeFronts

Loading…