30 CSS Hover Effects 20 / 30
CSS Color Channel Split Hover Effect
Four color channel separation effects on image containers — RGB duotone split, chromatic aberration text, green-screen channel extract, and full-color separation with mix-blend-mode — using CSS filter, mix-blend-mode, and pseudo-element tinting to deconstruct color into channels on hover.
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-20">
<div class="hv-20__grid">
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--rgb" data-text="SIGNAL">
<span class="hv-20__box-label">SIGNAL</span>
</div>
<span class="hv-20__label">RGB channel split</span>
</div>
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--chroma">
<span class="hv-20__chroma" data-text="CHROMATIC">CHROMATIC</span>
</div>
<span class="hv-20__label">text shadow aberration</span>
</div>
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--duo">
<span class="hv-20__box-label">DUOTONE</span>
</div>
<span class="hv-20__label">color grade shift</span>
</div>
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--screen">
<div class="hv-20__screen-r"></div>
<div class="hv-20__screen-b"></div>
<span class="hv-20__box-label">COMPOSITE</span>
</div>
<span class="hv-20__label">screen blend channels</span>
</div>
</div>
</div> <div class="hv-20">
<div class="hv-20__grid">
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--rgb" data-text="SIGNAL">
<span class="hv-20__box-label">SIGNAL</span>
</div>
<span class="hv-20__label">RGB channel split</span>
</div>
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--chroma">
<span class="hv-20__chroma" data-text="CHROMATIC">CHROMATIC</span>
</div>
<span class="hv-20__label">text shadow aberration</span>
</div>
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--duo">
<span class="hv-20__box-label">DUOTONE</span>
</div>
<span class="hv-20__label">color grade shift</span>
</div>
<div class="hv-20__cell">
<div class="hv-20__box hv-20__box--screen">
<div class="hv-20__screen-r"></div>
<div class="hv-20__screen-b"></div>
<span class="hv-20__box-label">COMPOSITE</span>
</div>
<span class="hv-20__label">screen blend channels</span>
</div>
</div>
</div>.hv-20,.hv-20 *,.hv-20 *::before,.hv-20 *::after{box-sizing:border-box;margin:0;padding:0}
.hv-20 ::selection{background:#dc2626;color:#fff}
.hv-20{
--bg:#050505;
--dim:#4b5563;
--red:#ff0040;
--green:#00ff88;
--blue:#0040ff;
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-20__grid{
display:grid;grid-template-columns:repeat(2,1fr);gap:40px;
max-width:720px;width:100%;
}
.hv-20__cell{
display:flex;flex-direction:column;align-items:center;gap:20px;
}
.hv-20__label{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.hv-20__box{
width:100%;aspect-ratio:4/3;border-radius:12px;
position:relative;overflow:hidden;cursor:pointer;
background:linear-gradient(135deg,#1a1a2e,#16213e,#0f3460,#533483);
display:flex;align-items:center;justify-content:center;
}
.hv-20__box-label{
position:relative;z-index:2;
font-size:1.2rem;font-weight:900;letter-spacing:.15em;
color:#fff;
}
/* 1 — RGB channel split via text-shadow ghosts on the label */
.hv-20__box--rgb{
background:
radial-gradient(circle at 30% 30%,#1e3a8a 0%,transparent 50%),
radial-gradient(circle at 70% 70%,#4c1d95 0%,transparent 50%),
linear-gradient(135deg,#0a0a1a,#1a0a2e);
}
.hv-20__box--rgb .hv-20__box-label{
transition:text-shadow .45s cubic-bezier(.4,0,.2,1),letter-spacing .45s;
text-shadow:0 0 0 transparent;
}
.hv-20__box--rgb:hover .hv-20__box-label{
letter-spacing:.22em;
text-shadow:
-6px 0 0 var(--red),
6px 0 0 var(--blue),
0 4px 0 var(--green);
}
/* 2 — chromatic text shadow (now in a card to match siblings) */
.hv-20__box--chroma{
background:radial-gradient(circle at 50% 50%,#1a1a2e 0%,#050505 100%);
cursor:default;
}
.hv-20__chroma{
font-size:clamp(1.4rem,4vw,1.8rem);font-weight:900;letter-spacing:.12em;
color:#fff;position:relative;display:inline-block;z-index:2;
transition:text-shadow .4s cubic-bezier(.4,0,.2,1),letter-spacing .4s;
}
.hv-20__box--chroma:hover .hv-20__chroma{
letter-spacing:.18em;
text-shadow:
5px 0 0 var(--red),
-5px 0 0 var(--blue),
0 4px 0 rgba(0,255,136,.6);
}
/* 3 — duotone grade (bright varied base so hue-rotate is visible) */
.hv-20__box--duo{
background:
radial-gradient(circle at 25% 30%,#fbbf24 0%,transparent 35%),
radial-gradient(circle at 75% 70%,#dc2626 0%,transparent 40%),
linear-gradient(135deg,#7c3aed,#ec4899,#f59e0b);
transition:filter .5s cubic-bezier(.4,0,.2,1);
}
.hv-20__box--duo:hover{
filter:hue-rotate(180deg) saturate(1.6);
}
.hv-20__box--duo .hv-20__box-label{
text-shadow:0 2px 8px rgba(0,0,0,.8);
}
/* 4 — screen composite */
.hv-20__screen-r,.hv-20__screen-b{
position:absolute;inset:0;
border-radius:50%;width:60%;height:60%;
opacity:0;
transition:opacity .4s,transform .5s cubic-bezier(.4,0,.2,1);
z-index:1;
}
.hv-20__screen-r{
background:var(--red);mix-blend-mode:screen;
top:10%;left:10%;
}
.hv-20__screen-b{
background:var(--blue);mix-blend-mode:screen;
top:10%;right:10%;left:auto;
}
.hv-20__box--screen:hover .hv-20__screen-r{opacity:.7;transform:translateX(-10px)}
.hv-20__box--screen:hover .hv-20__screen-b{opacity:.7;transform:translateX(10px)}
@media(max-width:520px){.hv-20__grid{grid-template-columns:1fr}}
@media(prefers-reduced-motion:reduce){
.hv-20__layer,.hv-20__screen-r,.hv-20__screen-b,.hv-20__box{transition:none!important}
.hv-20__chroma{transition:none!important}
} .hv-20,.hv-20 *,.hv-20 *::before,.hv-20 *::after{box-sizing:border-box;margin:0;padding:0}
.hv-20 ::selection{background:#dc2626;color:#fff}
.hv-20{
--bg:#050505;
--dim:#4b5563;
--red:#ff0040;
--green:#00ff88;
--blue:#0040ff;
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-20__grid{
display:grid;grid-template-columns:repeat(2,1fr);gap:40px;
max-width:720px;width:100%;
}
.hv-20__cell{
display:flex;flex-direction:column;align-items:center;gap:20px;
}
.hv-20__label{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim)}
.hv-20__box{
width:100%;aspect-ratio:4/3;border-radius:12px;
position:relative;overflow:hidden;cursor:pointer;
background:linear-gradient(135deg,#1a1a2e,#16213e,#0f3460,#533483);
display:flex;align-items:center;justify-content:center;
}
.hv-20__box-label{
position:relative;z-index:2;
font-size:1.2rem;font-weight:900;letter-spacing:.15em;
color:#fff;
}
/* 1 — RGB channel split via text-shadow ghosts on the label */
.hv-20__box--rgb{
background:
radial-gradient(circle at 30% 30%,#1e3a8a 0%,transparent 50%),
radial-gradient(circle at 70% 70%,#4c1d95 0%,transparent 50%),
linear-gradient(135deg,#0a0a1a,#1a0a2e);
}
.hv-20__box--rgb .hv-20__box-label{
transition:text-shadow .45s cubic-bezier(.4,0,.2,1),letter-spacing .45s;
text-shadow:0 0 0 transparent;
}
.hv-20__box--rgb:hover .hv-20__box-label{
letter-spacing:.22em;
text-shadow:
-6px 0 0 var(--red),
6px 0 0 var(--blue),
0 4px 0 var(--green);
}
/* 2 — chromatic text shadow (now in a card to match siblings) */
.hv-20__box--chroma{
background:radial-gradient(circle at 50% 50%,#1a1a2e 0%,#050505 100%);
cursor:default;
}
.hv-20__chroma{
font-size:clamp(1.4rem,4vw,1.8rem);font-weight:900;letter-spacing:.12em;
color:#fff;position:relative;display:inline-block;z-index:2;
transition:text-shadow .4s cubic-bezier(.4,0,.2,1),letter-spacing .4s;
}
.hv-20__box--chroma:hover .hv-20__chroma{
letter-spacing:.18em;
text-shadow:
5px 0 0 var(--red),
-5px 0 0 var(--blue),
0 4px 0 rgba(0,255,136,.6);
}
/* 3 — duotone grade (bright varied base so hue-rotate is visible) */
.hv-20__box--duo{
background:
radial-gradient(circle at 25% 30%,#fbbf24 0%,transparent 35%),
radial-gradient(circle at 75% 70%,#dc2626 0%,transparent 40%),
linear-gradient(135deg,#7c3aed,#ec4899,#f59e0b);
transition:filter .5s cubic-bezier(.4,0,.2,1);
}
.hv-20__box--duo:hover{
filter:hue-rotate(180deg) saturate(1.6);
}
.hv-20__box--duo .hv-20__box-label{
text-shadow:0 2px 8px rgba(0,0,0,.8);
}
/* 4 — screen composite */
.hv-20__screen-r,.hv-20__screen-b{
position:absolute;inset:0;
border-radius:50%;width:60%;height:60%;
opacity:0;
transition:opacity .4s,transform .5s cubic-bezier(.4,0,.2,1);
z-index:1;
}
.hv-20__screen-r{
background:var(--red);mix-blend-mode:screen;
top:10%;left:10%;
}
.hv-20__screen-b{
background:var(--blue);mix-blend-mode:screen;
top:10%;right:10%;left:auto;
}
.hv-20__box--screen:hover .hv-20__screen-r{opacity:.7;transform:translateX(-10px)}
.hv-20__box--screen:hover .hv-20__screen-b{opacity:.7;transform:translateX(10px)}
@media(max-width:520px){.hv-20__grid{grid-template-columns:1fr}}
@media(prefers-reduced-motion:reduce){
.hv-20__layer,.hv-20__screen-r,.hv-20__screen-b,.hv-20__box{transition:none!important}
.hv-20__chroma{transition:none!important}
}How this works
CSS can simulate RGB channel separation by duplicating an element and applying filter: url(#red-channel) or by overlaying colored pseudo-elements with mix-blend-mode: multiply. The practical pure-CSS approach tints a ::before with background: rgba(255,0,0,.5) and mix-blend-mode: multiply for the red channel, and a matching ::after in blue — transitioning these from opacity: 0 to opacity: 1 on hover reveals the channel tints over the base content.
The chromatic aberration text effect layers ::before and ::after with the element's text content and offsets them using text-shadow: 2px 0 var(--red) and -2px 0 var(--blue) combined with opacity transitions. No duplication is needed — the shadow offset creates the separated color fringing. On hover the shadow intensity increases from a subtle hint to a full separation.
Customize
- Increase channel offset for more separation by pushing
text-shadowfrom2pxto6px— or apply on both X and Y axes for a diagonal split. - Change split colors away from RGB by using
rgba(255,200,0)+rgba(0,100,255)for a gold/blue duotone split effect. - Apply the effect continuously (remove
:hoverrestriction) on an animation loop using a keyframe that oscillates the channel offset between -3px and 3px. - Reduce saturation on the base element with
filter: saturate(0.3)at rest and restore tosaturate(1)on hover — the color channels then feel like they're being reassembled. - Add a slight
blur(0.5px)to the offset channel layers for a softer, more optically accurate chromatic aberration feel.
Watch out for
mix-blend-modeon pseudo-elements blends with everything behind the element, not just the element itself — ensure the background behind the card is controlled to avoid unexpected blending.- The
multiplyblend mode only darkens — white channel tints over white content are invisible. Usescreenfor additive blending on dark backgrounds. - SVG
feColorMatrixfilters for true channel separation require inline SVG defs in the HTML — pure CSS cannot replicate exact single-channel extraction without SVG filters.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 60+ | 12+ | 60+ | 60+ |
mix-blend-mode is fully supported in modern browsers. The SVG feColorMatrix approach needs inline SVG in HTML.