30 CSS Hover Effects16 / 30
CSS Spotlight Card Hover Effect
Four spotlight and lighting hover effects on cards — radial gradient center spotlight, corner-origin light sweep, edge scanline, and vignette-lift — using CSS radial-gradient pseudo-elements to simulate a focused light source illuminating the card face on hover.
Published
This is a full-page demo — interact inside the frame above, or open it in the playground for the full-screen experience.
The code
<div class="hv-16">
<div class="hv-16__grid">
<div class="hv-16__card hv-16__card--center">
<div class="hv-16__content">
<div class="hv-16__icon">◎</div>
<h3 class="hv-16__title">Center Spot</h3>
<p class="hv-16__text">Radial gradient fades in from the center on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--corner">
<div class="hv-16__content">
<div class="hv-16__icon">◤</div>
<h3 class="hv-16__title">Corner Light</h3>
<p class="hv-16__text">Conic light sweep from the top-left corner lamp.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--scan">
<div class="hv-16__content">
<div class="hv-16__icon">▤</div>
<h3 class="hv-16__title">Edge Scan</h3>
<p class="hv-16__text">Bright scan band sweeps top to bottom on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--vignette">
<div class="hv-16__content">
<div class="hv-16__icon">◉</div>
<h3 class="hv-16__title">Vignette Lift</h3>
<p class="hv-16__text">Dark vignette fades out revealing the full card face.</p>
</div>
</div>
</div>
</div><div class="hv-16">
<div class="hv-16__grid">
<div class="hv-16__card hv-16__card--center">
<div class="hv-16__content">
<div class="hv-16__icon">◎</div>
<h3 class="hv-16__title">Center Spot</h3>
<p class="hv-16__text">Radial gradient fades in from the center on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--corner">
<div class="hv-16__content">
<div class="hv-16__icon">◤</div>
<h3 class="hv-16__title">Corner Light</h3>
<p class="hv-16__text">Conic light sweep from the top-left corner lamp.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--scan">
<div class="hv-16__content">
<div class="hv-16__icon">▤</div>
<h3 class="hv-16__title">Edge Scan</h3>
<p class="hv-16__text">Bright scan band sweeps top to bottom on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--vignette">
<div class="hv-16__content">
<div class="hv-16__icon">◉</div>
<h3 class="hv-16__title">Vignette Lift</h3>
<p class="hv-16__text">Dark vignette fades out revealing the full card face.</p>
</div>
</div>
</div>
</div>.hv-16,
.hv-16 *,
.hv-16 *::before,
.hv-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.hv-16 ::selection {
background: #0f766e;
color: #fff;
}
.hv-16 {
--bg: #020c0b;
--text: #ccfbf1;
--dim: #6b7280;
--teal: #14b8a6;
--green: #10b981;
--cyan: #06b6d4;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 60px 24px;
}
.hv-16__grid {
display: grid;
grid-template-columns: repeat(2,1fr);
gap: 32px;
max-width: 720px;
width: 100%;
}
/* shared card */
.hv-16__card {
position: relative;
overflow: hidden;
min-height: 220px;
border-radius: 16px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.1);
cursor: pointer;
transition: border-color .4s,transform .4s;
}
.hv-16__card:hover {
border-color: rgba(20,184,166,.3);
transform: translateY(-4px);
}
.hv-16__card::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
transition: opacity .4s;
}
.hv-16__content {
position: relative;
z-index: 1;
padding: 32px;
display: flex;
flex-direction: column;
gap: 12px;
}
.hv-16__icon {
font-size: 1.8rem;
color: var(--teal);
}
.hv-16__title {
font-size: 1.05rem;
font-weight: 700;
color: var(--text);
}
.hv-16__text {
font-size: .85rem;
color: var(--dim);
line-height: 1.5;
}
/* 1 — center spotlight */
.hv-16__card--center::before {
background: radial-gradient(circle at 50% 50%,rgba(20,184,166,.18) 0%,transparent 65%);
opacity: 0;
}
.hv-16__card--center:hover::before {
opacity: 1;
}
/* 2 — corner sweep */
.hv-16__card--corner::before {
background: conic-gradient(from 225deg at 0% 0%,rgba(6,182,212,.25),transparent 40%);
opacity: 0;
}
.hv-16__card--corner:hover::before {
opacity: 1;
}
/* 3 — scan band */
.hv-16__card--scan::before {
background: linear-gradient(180deg,transparent 0%,rgba(20,184,166,.15) 40%,rgba(20,184,166,.15) 60%,transparent 100%);
opacity: 0;
transform: translateY(-100%);
transition: opacity .3s,transform .5s cubic-bezier(.4,0,.2,1);
}
.hv-16__card--scan:hover::before {
opacity: 1;
transform: translateY(60%);
}
/* 4 — vignette lift */
.hv-16__card--vignette::before {
background: radial-gradient(ellipse at center,transparent 40%,rgba(0,0,0,.7) 100%);
opacity: 1;
transition: opacity .4s;
}
.hv-16__card--vignette:hover::before {
opacity: 0;
}
@media (max-width: 520px) {
.hv-16__grid {
grid-template-columns: 1fr;
}
}
@media (prefers-reduced-motion: reduce) {
.hv-16__card,
.hv-16__card::before {
transition: none!important;
}
}.hv-16,
.hv-16 *,
.hv-16 *::before,
.hv-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.hv-16 ::selection {
background: #0f766e;
color: #fff;
}
.hv-16 {
--bg: #020c0b;
--text: #ccfbf1;
--dim: #6b7280;
--teal: #14b8a6;
--green: #10b981;
--cyan: #06b6d4;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 60px 24px;
}
.hv-16__grid {
display: grid;
grid-template-columns: repeat(2,1fr);
gap: 32px;
max-width: 720px;
width: 100%;
}
/* shared card */
.hv-16__card {
position: relative;
overflow: hidden;
min-height: 220px;
border-radius: 16px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.1);
cursor: pointer;
transition: border-color .4s,transform .4s;
}
.hv-16__card:hover {
border-color: rgba(20,184,166,.3);
transform: translateY(-4px);
}
.hv-16__card::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
transition: opacity .4s;
}
.hv-16__content {
position: relative;
z-index: 1;
padding: 32px;
display: flex;
flex-direction: column;
gap: 12px;
}
.hv-16__icon {
font-size: 1.8rem;
color: var(--teal);
}
.hv-16__title {
font-size: 1.05rem;
font-weight: 700;
color: var(--text);
}
.hv-16__text {
font-size: .85rem;
color: var(--dim);
line-height: 1.5;
}
/* 1 — center spotlight */
.hv-16__card--center::before {
background: radial-gradient(circle at 50% 50%,rgba(20,184,166,.18) 0%,transparent 65%);
opacity: 0;
}
.hv-16__card--center:hover::before {
opacity: 1;
}
/* 2 — corner sweep */
.hv-16__card--corner::before {
background: conic-gradient(from 225deg at 0% 0%,rgba(6,182,212,.25),transparent 40%);
opacity: 0;
}
.hv-16__card--corner:hover::before {
opacity: 1;
}
/* 3 — scan band */
.hv-16__card--scan::before {
background: linear-gradient(180deg,transparent 0%,rgba(20,184,166,.15) 40%,rgba(20,184,166,.15) 60%,transparent 100%);
opacity: 0;
transform: translateY(-100%);
transition: opacity .3s,transform .5s cubic-bezier(.4,0,.2,1);
}
.hv-16__card--scan:hover::before {
opacity: 1;
transform: translateY(60%);
}
/* 4 — vignette lift */
.hv-16__card--vignette::before {
background: radial-gradient(ellipse at center,transparent 40%,rgba(0,0,0,.7) 100%);
opacity: 1;
transition: opacity .4s;
}
.hv-16__card--vignette:hover::before {
opacity: 0;
}
@media (max-width: 520px) {
.hv-16__grid {
grid-template-columns: 1fr;
}
}
@media (prefers-reduced-motion: reduce) {
.hv-16__card,
.hv-16__card::before {
transition: none!important;
}
}Here's a working CSS 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 Spotlight Card Hover Effect
Source: https://codefronts.com/motion/css-hover-effects/css-spotlight-card-hover-effect/
Four spotlight and lighting hover effects on cards — radial gradient center spotlight, corner-origin light sweep, edge scanline, and vignette-lift — using CSS radial-gradient pseudo-elements to simulate a focused light source illuminating the card face on hover.
## HTML
```html
<div class="hv-16">
<div class="hv-16__grid">
<div class="hv-16__card hv-16__card--center">
<div class="hv-16__content">
<div class="hv-16__icon">◎</div>
<h3 class="hv-16__title">Center Spot</h3>
<p class="hv-16__text">Radial gradient fades in from the center on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--corner">
<div class="hv-16__content">
<div class="hv-16__icon">◤</div>
<h3 class="hv-16__title">Corner Light</h3>
<p class="hv-16__text">Conic light sweep from the top-left corner lamp.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--scan">
<div class="hv-16__content">
<div class="hv-16__icon">▤</div>
<h3 class="hv-16__title">Edge Scan</h3>
<p class="hv-16__text">Bright scan band sweeps top to bottom on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--vignette">
<div class="hv-16__content">
<div class="hv-16__icon">◉</div>
<h3 class="hv-16__title">Vignette Lift</h3>
<p class="hv-16__text">Dark vignette fades out revealing the full card face.</p>
</div>
</div>
</div>
</div>
```
## CSS
```css
.hv-16,
.hv-16 *,
.hv-16 *::before,
.hv-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.hv-16 ::selection {
background: #0f766e;
color: #fff;
}
.hv-16 {
--bg: #020c0b;
--text: #ccfbf1;
--dim: #6b7280;
--teal: #14b8a6;
--green: #10b981;
--cyan: #06b6d4;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 60px 24px;
}
.hv-16__grid {
display: grid;
grid-template-columns: repeat(2,1fr);
gap: 32px;
max-width: 720px;
width: 100%;
}
/* shared card */
.hv-16__card {
position: relative;
overflow: hidden;
min-height: 220px;
border-radius: 16px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.1);
cursor: pointer;
transition: border-color .4s,transform .4s;
}
.hv-16__card:hover {
border-color: rgba(20,184,166,.3);
transform: translateY(-4px);
}
.hv-16__card::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
transition: opacity .4s;
}
.hv-16__content {
position: relative;
z-index: 1;
padding: 32px;
display: flex;
flex-direction: column;
gap: 12px;
}
.hv-16__icon {
font-size: 1.8rem;
color: var(--teal);
}
.hv-16__title {
font-size: 1.05rem;
font-weight: 700;
color: var(--text);
}
.hv-16__text {
font-size: .85rem;
color: var(--dim);
line-height: 1.5;
}
/* 1 — center spotlight */
.hv-16__card--center::before {
background: radial-gradient(circle at 50% 50%,rgba(20,184,166,.18) 0%,transparent 65%);
opacity: 0;
}
.hv-16__card--center:hover::before {
opacity: 1;
}
/* 2 — corner sweep */
.hv-16__card--corner::before {
background: conic-gradient(from 225deg at 0% 0%,rgba(6,182,212,.25),transparent 40%);
opacity: 0;
}
.hv-16__card--corner:hover::before {
opacity: 1;
}
/* 3 — scan band */
.hv-16__card--scan::before {
background: linear-gradient(180deg,transparent 0%,rgba(20,184,166,.15) 40%,rgba(20,184,166,.15) 60%,transparent 100%);
opacity: 0;
transform: translateY(-100%);
transition: opacity .3s,transform .5s cubic-bezier(.4,0,.2,1);
}
.hv-16__card--scan:hover::before {
opacity: 1;
transform: translateY(60%);
}
/* 4 — vignette lift */
.hv-16__card--vignette::before {
background: radial-gradient(ellipse at center,transparent 40%,rgba(0,0,0,.7) 100%);
opacity: 1;
transition: opacity .4s;
}
.hv-16__card--vignette:hover::before {
opacity: 0;
}
@media (max-width: 520px) {
.hv-16__grid {
grid-template-columns: 1fr;
}
}
@media (prefers-reduced-motion: reduce) {
.hv-16__card,
.hv-16__card::before {
transition: none!important;
}
}
```Here's a working CSS 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 Spotlight Card Hover Effect
Source: https://codefronts.com/motion/css-hover-effects/css-spotlight-card-hover-effect/
Four spotlight and lighting hover effects on cards — radial gradient center spotlight, corner-origin light sweep, edge scanline, and vignette-lift — using CSS radial-gradient pseudo-elements to simulate a focused light source illuminating the card face on hover.
## HTML
```html
<div class="hv-16">
<div class="hv-16__grid">
<div class="hv-16__card hv-16__card--center">
<div class="hv-16__content">
<div class="hv-16__icon">◎</div>
<h3 class="hv-16__title">Center Spot</h3>
<p class="hv-16__text">Radial gradient fades in from the center on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--corner">
<div class="hv-16__content">
<div class="hv-16__icon">◤</div>
<h3 class="hv-16__title">Corner Light</h3>
<p class="hv-16__text">Conic light sweep from the top-left corner lamp.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--scan">
<div class="hv-16__content">
<div class="hv-16__icon">▤</div>
<h3 class="hv-16__title">Edge Scan</h3>
<p class="hv-16__text">Bright scan band sweeps top to bottom on hover.</p>
</div>
</div>
<div class="hv-16__card hv-16__card--vignette">
<div class="hv-16__content">
<div class="hv-16__icon">◉</div>
<h3 class="hv-16__title">Vignette Lift</h3>
<p class="hv-16__text">Dark vignette fades out revealing the full card face.</p>
</div>
</div>
</div>
</div>
```
## CSS
```css
.hv-16,
.hv-16 *,
.hv-16 *::before,
.hv-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.hv-16 ::selection {
background: #0f766e;
color: #fff;
}
.hv-16 {
--bg: #020c0b;
--text: #ccfbf1;
--dim: #6b7280;
--teal: #14b8a6;
--green: #10b981;
--cyan: #06b6d4;
font-family: 'Segoe UI',system-ui,sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 60px 24px;
}
.hv-16__grid {
display: grid;
grid-template-columns: repeat(2,1fr);
gap: 32px;
max-width: 720px;
width: 100%;
}
/* shared card */
.hv-16__card {
position: relative;
overflow: hidden;
min-height: 220px;
border-radius: 16px;
background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.1);
cursor: pointer;
transition: border-color .4s,transform .4s;
}
.hv-16__card:hover {
border-color: rgba(20,184,166,.3);
transform: translateY(-4px);
}
.hv-16__card::before {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
transition: opacity .4s;
}
.hv-16__content {
position: relative;
z-index: 1;
padding: 32px;
display: flex;
flex-direction: column;
gap: 12px;
}
.hv-16__icon {
font-size: 1.8rem;
color: var(--teal);
}
.hv-16__title {
font-size: 1.05rem;
font-weight: 700;
color: var(--text);
}
.hv-16__text {
font-size: .85rem;
color: var(--dim);
line-height: 1.5;
}
/* 1 — center spotlight */
.hv-16__card--center::before {
background: radial-gradient(circle at 50% 50%,rgba(20,184,166,.18) 0%,transparent 65%);
opacity: 0;
}
.hv-16__card--center:hover::before {
opacity: 1;
}
/* 2 — corner sweep */
.hv-16__card--corner::before {
background: conic-gradient(from 225deg at 0% 0%,rgba(6,182,212,.25),transparent 40%);
opacity: 0;
}
.hv-16__card--corner:hover::before {
opacity: 1;
}
/* 3 — scan band */
.hv-16__card--scan::before {
background: linear-gradient(180deg,transparent 0%,rgba(20,184,166,.15) 40%,rgba(20,184,166,.15) 60%,transparent 100%);
opacity: 0;
transform: translateY(-100%);
transition: opacity .3s,transform .5s cubic-bezier(.4,0,.2,1);
}
.hv-16__card--scan:hover::before {
opacity: 1;
transform: translateY(60%);
}
/* 4 — vignette lift */
.hv-16__card--vignette::before {
background: radial-gradient(ellipse at center,transparent 40%,rgba(0,0,0,.7) 100%);
opacity: 1;
transition: opacity .4s;
}
.hv-16__card--vignette:hover::before {
opacity: 0;
}
@media (max-width: 520px) {
.hv-16__grid {
grid-template-columns: 1fr;
}
}
@media (prefers-reduced-motion: reduce) {
.hv-16__card,
.hv-16__card::before {
transition: none!important;
}
}
```How this works
The spotlight effect uses a ::before pseudo-element with background: radial-gradient(circle at 50% 50%, rgba(255,255,255,.15) 0%, transparent 65%) and opacity: 0 at rest. On hover, opacity: 1 fades the gradient in, creating the impression of a direct light beam hitting the card from above. The mix-blend-mode: overlay on the pseudo-element blends the white circle into the card content, brightening both the background and the text simultaneously.
The corner light sweeps a conic-gradient(from 225deg at 0% 0%, rgba(255,255,255,.2), transparent 40%) from zero opacity to full, simulating a lamp positioned at the top-left corner. The vignette-lift inverts the approach: the resting state has a dark radial-gradient(ellipse at center, transparent 40%, rgba(0,0,0,.6) 100%) vignette that fades out on hover, making the card face appear to illuminate as it lifts.
Make it yours
- Move the spotlight to a fixed corner by changing
circle at 50% 50%tocircle at 80% 20%for a top-right light source position. - Tint the spotlight by replacing
rgba(255,255,255,.15)with a colored rgba — a warmrgba(255,200,100,.12)reads as incandescent. - Increase spotlight size by widening the gradient spread —
circle at 50% 30%with a stop at80%creates a floodlight rather than a focused spot. - Combine with a
transform: translateZ(10px)on hover for a subtle 3D lift that pairs naturally with the lighting illusion. - Add a second pseudo-element using
::afteras a softer fill light from the opposite corner for a two-point lighting setup.
Gotchas — read before shipping
mix-blend-mode: overlayon the spotlight pseudo-element requires the parent to have a non-transparent background — on transparent containers the blend has nothing to composite against.- The spotlight
::beforemust bepointer-events: noneto avoid blocking clicks on interactive children like buttons inside the card. - Very high opacity radial gradients (
.5+) can wash out dark-colored text — keep the spotlight highlight below.2opacity and rely on the large radius for spread.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 60+ | 12+ | 60+ | 60+ |
radial-gradient and mix-blend-mode are universally supported in modern browsers.