31 CSS Hero Sections29 / 31
Glitch Text Hero
VHS-glitch hero — RGB-channel offsets create a tape-static glitch effect. VHS red and tape blue against a static-gray background, the analogue cyberpunk treatment.
Published
The code
<section class="hs-29" aria-label="Hero">
<span class="hs-29__static" aria-hidden="true"></span>
<span class="hs-29__scan" aria-hidden="true"></span>
<div class="hs-29__inner">
<span class="hs-29__eye">REC ● 00:42:18</span>
<h2 data-text="LOST & FOUND" class="hs-29__h">LOST & FOUND</h2>
<p>
A search engine for VHS-era ephemera. Public-access TV, mall demos, regional news. The
forgotten internet of the 80s.
</p>
<a class="hs-29__cta" href="#search">Search the tapes →</a>
</div>
</section><section class="hs-29" aria-label="Hero">
<span class="hs-29__static" aria-hidden="true"></span>
<span class="hs-29__scan" aria-hidden="true"></span>
<div class="hs-29__inner">
<span class="hs-29__eye">REC ● 00:42:18</span>
<h2 data-text="LOST & FOUND" class="hs-29__h">LOST & FOUND</h2>
<p>
A search engine for VHS-era ephemera. Public-access TV, mall demos, regional news. The
forgotten internet of the 80s.
</p>
<a class="hs-29__cta" href="#search">Search the tapes →</a>
</div>
</section>.hs-29 {
position: relative;
overflow: hidden;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px);
background: #1a1818;
font-family: 'JetBrains Mono', monospace;
color: #d8d4c8;
box-sizing: border-box;
contain: layout paint;
}
.hs-29__static {
position: absolute;
inset: 0;
background-image: radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px), radial-gradient(rgba(255,255,255,0.03) 1px, transparent 1px);
background-size: 3px 3px, 5px 5px;
background-position: 0 0, 1px 1px;
pointer-events: none;
animation: hs-29-jit 0.2s steps(2) infinite;
}
.hs-29__scan {
position: absolute;
inset: 0;
background: repeating-linear-gradient(180deg, transparent 0 2px, rgba(0,0,0,0.18) 2px 3px);
pointer-events: none;
}
@keyframes hs-29-jit {
0% {
transform: translate(0,0);
}
50% {
transform: translate(-1px,1px);
}
100% {
transform: translate(1px,-1px);
}
}
.hs-29__inner {
position: relative;
z-index: 1;
max-width: 640px;
text-align: center;
}
.hs-29__eye {
display: inline-block;
padding: 4px 10px;
background: #d63838;
color: #fff;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.18em;
margin-bottom: 22px;
animation: hs-29-blink 1.4s steps(2) infinite;
}
@keyframes hs-29-blink {
to {
opacity: 0.5;
}
}
.hs-29__h {
position: relative;
margin: 0 0 18px;
font-family: 'Inter', sans-serif;
font-size: clamp(48px, 9vw, 100px);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 0.92;
color: #f0eee0;
}
.hs-29__h::before,
.hs-29__h::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
text-align: center;
}
.hs-29__h::before {
color: #d63838;
transform: translate(-3px,0);
clip-path: polygon(0 12%, 100% 12%, 100% 38%, 0 38%);
animation: hs-29-rgb 2.4s ease-in-out infinite;
}
.hs-29__h::after {
color: #38b8d6;
transform: translate(3px,0);
clip-path: polygon(0 56%, 100% 56%, 100% 88%, 0 88%);
animation: hs-29-rgb 2.4s ease-in-out infinite reverse;
}
@keyframes hs-29-rgb {
0%,
100% {
transform: translate(-3px,0);
}
50% {
transform: translate(3px,2px);
}
}
.hs-29 p {
margin: 0 auto 24px;
font-size: 14px;
line-height: 1.6;
color: #98948c;
max-width: 460px;
}
.hs-29__cta {
display: inline-block;
padding: 12px 22px;
background: #38b8d6;
color: #1a1818;
border-radius: 0;
text-decoration: none;
font-weight: 800;
font-size: 13px;
letter-spacing: 0.16em;
text-transform: uppercase;
transition: background 0.15s, color 0.15s;
}
.hs-29__cta:hover {
background: #d63838;
color: #fff;
}
@media (prefers-reduced-motion: reduce) {
.hs-29__static,
.hs-29__eye,
.hs-29__h::before,
.hs-29__h::after {
animation: none;
}
.hs-29__cta {
transition: none;
}
}.hs-29 {
position: relative;
overflow: hidden;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px);
background: #1a1818;
font-family: 'JetBrains Mono', monospace;
color: #d8d4c8;
box-sizing: border-box;
contain: layout paint;
}
.hs-29__static {
position: absolute;
inset: 0;
background-image: radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px), radial-gradient(rgba(255,255,255,0.03) 1px, transparent 1px);
background-size: 3px 3px, 5px 5px;
background-position: 0 0, 1px 1px;
pointer-events: none;
animation: hs-29-jit 0.2s steps(2) infinite;
}
.hs-29__scan {
position: absolute;
inset: 0;
background: repeating-linear-gradient(180deg, transparent 0 2px, rgba(0,0,0,0.18) 2px 3px);
pointer-events: none;
}
@keyframes hs-29-jit {
0% {
transform: translate(0,0);
}
50% {
transform: translate(-1px,1px);
}
100% {
transform: translate(1px,-1px);
}
}
.hs-29__inner {
position: relative;
z-index: 1;
max-width: 640px;
text-align: center;
}
.hs-29__eye {
display: inline-block;
padding: 4px 10px;
background: #d63838;
color: #fff;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.18em;
margin-bottom: 22px;
animation: hs-29-blink 1.4s steps(2) infinite;
}
@keyframes hs-29-blink {
to {
opacity: 0.5;
}
}
.hs-29__h {
position: relative;
margin: 0 0 18px;
font-family: 'Inter', sans-serif;
font-size: clamp(48px, 9vw, 100px);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 0.92;
color: #f0eee0;
}
.hs-29__h::before,
.hs-29__h::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
text-align: center;
}
.hs-29__h::before {
color: #d63838;
transform: translate(-3px,0);
clip-path: polygon(0 12%, 100% 12%, 100% 38%, 0 38%);
animation: hs-29-rgb 2.4s ease-in-out infinite;
}
.hs-29__h::after {
color: #38b8d6;
transform: translate(3px,0);
clip-path: polygon(0 56%, 100% 56%, 100% 88%, 0 88%);
animation: hs-29-rgb 2.4s ease-in-out infinite reverse;
}
@keyframes hs-29-rgb {
0%,
100% {
transform: translate(-3px,0);
}
50% {
transform: translate(3px,2px);
}
}
.hs-29 p {
margin: 0 auto 24px;
font-size: 14px;
line-height: 1.6;
color: #98948c;
max-width: 460px;
}
.hs-29__cta {
display: inline-block;
padding: 12px 22px;
background: #38b8d6;
color: #1a1818;
border-radius: 0;
text-decoration: none;
font-weight: 800;
font-size: 13px;
letter-spacing: 0.16em;
text-transform: uppercase;
transition: background 0.15s, color 0.15s;
}
.hs-29__cta:hover {
background: #d63838;
color: #fff;
}
@media (prefers-reduced-motion: reduce) {
.hs-29__static,
.hs-29__eye,
.hs-29__h::before,
.hs-29__h::after {
animation: none;
}
.hs-29__cta {
transition: none;
}
}Here's a working CSS Hero Section 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: Glitch Text Hero
Source: https://codefronts.com/layouts/css-hero-sections/glitch-text-hero/
VHS-glitch hero — RGB-channel offsets create a tape-static glitch effect. VHS red and tape blue against a static-gray background, the analogue cyberpunk treatment.
## HTML
```html
<section class="hs-29" aria-label="Hero">
<span class="hs-29__static" aria-hidden="true"></span>
<span class="hs-29__scan" aria-hidden="true"></span>
<div class="hs-29__inner">
<span class="hs-29__eye">REC ● 00:42:18</span>
<h2 data-text="LOST & FOUND" class="hs-29__h">LOST & FOUND</h2>
<p>
A search engine for VHS-era ephemera. Public-access TV, mall demos, regional news. The
forgotten internet of the 80s.
</p>
<a class="hs-29__cta" href="#search">Search the tapes →</a>
</div>
</section>
```
## CSS
```css
.hs-29 {
position: relative;
overflow: hidden;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px);
background: #1a1818;
font-family: 'JetBrains Mono', monospace;
color: #d8d4c8;
box-sizing: border-box;
contain: layout paint;
}
.hs-29__static {
position: absolute;
inset: 0;
background-image: radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px), radial-gradient(rgba(255,255,255,0.03) 1px, transparent 1px);
background-size: 3px 3px, 5px 5px;
background-position: 0 0, 1px 1px;
pointer-events: none;
animation: hs-29-jit 0.2s steps(2) infinite;
}
.hs-29__scan {
position: absolute;
inset: 0;
background: repeating-linear-gradient(180deg, transparent 0 2px, rgba(0,0,0,0.18) 2px 3px);
pointer-events: none;
}
@keyframes hs-29-jit {
0% {
transform: translate(0,0);
}
50% {
transform: translate(-1px,1px);
}
100% {
transform: translate(1px,-1px);
}
}
.hs-29__inner {
position: relative;
z-index: 1;
max-width: 640px;
text-align: center;
}
.hs-29__eye {
display: inline-block;
padding: 4px 10px;
background: #d63838;
color: #fff;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.18em;
margin-bottom: 22px;
animation: hs-29-blink 1.4s steps(2) infinite;
}
@keyframes hs-29-blink {
to {
opacity: 0.5;
}
}
.hs-29__h {
position: relative;
margin: 0 0 18px;
font-family: 'Inter', sans-serif;
font-size: clamp(48px, 9vw, 100px);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 0.92;
color: #f0eee0;
}
.hs-29__h::before,
.hs-29__h::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
text-align: center;
}
.hs-29__h::before {
color: #d63838;
transform: translate(-3px,0);
clip-path: polygon(0 12%, 100% 12%, 100% 38%, 0 38%);
animation: hs-29-rgb 2.4s ease-in-out infinite;
}
.hs-29__h::after {
color: #38b8d6;
transform: translate(3px,0);
clip-path: polygon(0 56%, 100% 56%, 100% 88%, 0 88%);
animation: hs-29-rgb 2.4s ease-in-out infinite reverse;
}
@keyframes hs-29-rgb {
0%,
100% {
transform: translate(-3px,0);
}
50% {
transform: translate(3px,2px);
}
}
.hs-29 p {
margin: 0 auto 24px;
font-size: 14px;
line-height: 1.6;
color: #98948c;
max-width: 460px;
}
.hs-29__cta {
display: inline-block;
padding: 12px 22px;
background: #38b8d6;
color: #1a1818;
border-radius: 0;
text-decoration: none;
font-weight: 800;
font-size: 13px;
letter-spacing: 0.16em;
text-transform: uppercase;
transition: background 0.15s, color 0.15s;
}
.hs-29__cta:hover {
background: #d63838;
color: #fff;
}
@media (prefers-reduced-motion: reduce) {
.hs-29__static,
.hs-29__eye,
.hs-29__h::before,
.hs-29__h::after {
animation: none;
}
.hs-29__cta {
transition: none;
}
}
```Here's a working CSS Hero Section 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: Glitch Text Hero
Source: https://codefronts.com/layouts/css-hero-sections/glitch-text-hero/
VHS-glitch hero — RGB-channel offsets create a tape-static glitch effect. VHS red and tape blue against a static-gray background, the analogue cyberpunk treatment.
## HTML
```html
<section class="hs-29" aria-label="Hero">
<span class="hs-29__static" aria-hidden="true"></span>
<span class="hs-29__scan" aria-hidden="true"></span>
<div class="hs-29__inner">
<span class="hs-29__eye">REC ● 00:42:18</span>
<h2 data-text="LOST & FOUND" class="hs-29__h">LOST & FOUND</h2>
<p>
A search engine for VHS-era ephemera. Public-access TV, mall demos, regional news. The
forgotten internet of the 80s.
</p>
<a class="hs-29__cta" href="#search">Search the tapes →</a>
</div>
</section>
```
## CSS
```css
.hs-29 {
position: relative;
overflow: hidden;
display: grid;
place-items: center;
width: 100%;
min-height: 100vh;
padding: clamp(28px, 5vw, 64px) clamp(20px, 5vw, 56px);
background: #1a1818;
font-family: 'JetBrains Mono', monospace;
color: #d8d4c8;
box-sizing: border-box;
contain: layout paint;
}
.hs-29__static {
position: absolute;
inset: 0;
background-image: radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px), radial-gradient(rgba(255,255,255,0.03) 1px, transparent 1px);
background-size: 3px 3px, 5px 5px;
background-position: 0 0, 1px 1px;
pointer-events: none;
animation: hs-29-jit 0.2s steps(2) infinite;
}
.hs-29__scan {
position: absolute;
inset: 0;
background: repeating-linear-gradient(180deg, transparent 0 2px, rgba(0,0,0,0.18) 2px 3px);
pointer-events: none;
}
@keyframes hs-29-jit {
0% {
transform: translate(0,0);
}
50% {
transform: translate(-1px,1px);
}
100% {
transform: translate(1px,-1px);
}
}
.hs-29__inner {
position: relative;
z-index: 1;
max-width: 640px;
text-align: center;
}
.hs-29__eye {
display: inline-block;
padding: 4px 10px;
background: #d63838;
color: #fff;
font-size: 11px;
font-weight: 700;
letter-spacing: 0.18em;
margin-bottom: 22px;
animation: hs-29-blink 1.4s steps(2) infinite;
}
@keyframes hs-29-blink {
to {
opacity: 0.5;
}
}
.hs-29__h {
position: relative;
margin: 0 0 18px;
font-family: 'Inter', sans-serif;
font-size: clamp(48px, 9vw, 100px);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 0.92;
color: #f0eee0;
}
.hs-29__h::before,
.hs-29__h::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
right: 0;
pointer-events: none;
text-align: center;
}
.hs-29__h::before {
color: #d63838;
transform: translate(-3px,0);
clip-path: polygon(0 12%, 100% 12%, 100% 38%, 0 38%);
animation: hs-29-rgb 2.4s ease-in-out infinite;
}
.hs-29__h::after {
color: #38b8d6;
transform: translate(3px,0);
clip-path: polygon(0 56%, 100% 56%, 100% 88%, 0 88%);
animation: hs-29-rgb 2.4s ease-in-out infinite reverse;
}
@keyframes hs-29-rgb {
0%,
100% {
transform: translate(-3px,0);
}
50% {
transform: translate(3px,2px);
}
}
.hs-29 p {
margin: 0 auto 24px;
font-size: 14px;
line-height: 1.6;
color: #98948c;
max-width: 460px;
}
.hs-29__cta {
display: inline-block;
padding: 12px 22px;
background: #38b8d6;
color: #1a1818;
border-radius: 0;
text-decoration: none;
font-weight: 800;
font-size: 13px;
letter-spacing: 0.16em;
text-transform: uppercase;
transition: background 0.15s, color 0.15s;
}
.hs-29__cta:hover {
background: #d63838;
color: #fff;
}
@media (prefers-reduced-motion: reduce) {
.hs-29__static,
.hs-29__eye,
.hs-29__h::before,
.hs-29__h::after {
animation: none;
}
.hs-29__cta {
transition: none;
}
}
```How this works
This glitch text hero section builds the RGB-shift effect from a single <h2 data-text="LOST & FOUND"> plus two pseudo-elements that read the same text via content: attr(data-text). The ::before layer renders in VHS red (#d63838) with transform: translate(-3px, 0) and clips to the upper band (clip-path: polygon(0 12%, 100% 12%, 100% 38%, 0 38%)). The ::after layer renders in tape blue (#38b8d6) with the opposite offset and clips to a lower band (56%-88%). Both animate the hs-29-rgb keyframe (2.4s ease-in-out, one running reverse) so the channels drift out of sync — the classic Cyberpunk-2077 / Chromatic-Aberration signature.
Two absolutely-positioned overlays sit on top of the whole section: .hs-29__static paints two stacked radial-gradient dot patterns (3px × 3px and 5px × 5px grids) and animates the hs-29-jit keyframe (steps(2) jitter at 0.2s intervals — no interpolation, pure snap) so the noise reads as VHS tape grain. .hs-29__scan paints a repeating-linear-gradient of 2-3px horizontal bands at 18% black to add scanlines. Background is static gray (#1a1818) not black — a critical detail; pure black kills the tape-noise contrast. The REC ● 00:42:18 eyebrow uses hs-29-blink (opacity 1 → 0.5 on steps(2)) so it flashes like a recording indicator.
Why it converts: glitch signals "cutting edge" for tech-adjacent audiences — the same visual language as Cyberpunk 2077, Web3 mint pages, and creative-coding portfolios. The RGB-shift specifically taps nostalgia for VHS-era media, which is the fastest-growing aesthetic in Gen Z / millennial creative markets. Single tape-blue CTA against the red RGB channel is the highest-contrast conversion path.
Make it yours
- Recolor to your brand by editing three values: VHS red (
#d63838), tape blue (#38b8d6), and static gray (#1a1818). For Web3 mint → red to#7b3ff2purple, blue to#00f0ffcyan. For hacker aesthetic → red to#ff003c, blue to#00ff88. Keep the RGB offset direction opposite — that's the chromatic aberration signature. - Swap the display sans: Inter 900 reads as "modern glitch." For pure cyberpunk →
'Space Grotesk'or'Anton'. For Web3 →'Syne'800. For retro-VHS →'VT323'monospace (matches the aesthetic but sacrifices the sharp glitch band). Keep thefont-weight: 900— thin weights lose the RGB-shift readability. - Change the CTA:
border-radius: 0is the brutalist / VHS-tape button standard. Bump toborder-radius: 4pxfor retro-gaming warmth. Addbox-shadow: 4px 4px 0 #d63838for a stamped-poster effect that layers the two accent colors. For maximum tension, animate the CTA background between red/blue on hover to mirror the RGB shift. - For light mode: this pattern doesn't invert cleanly — RGB-shift needs a dark backdrop. If you must ship a light variant, swap to
#f0e8dcpaper base with#8a1a1adeep-red and#1a5a6ateal channels, and dial the noise opacity from0.04down to0.02. The result reads as "risograph print," not glitch. - For Tailwind:
relative overflow-hidden grid place-items-center bg-[#1a1818] font-mono contain-[layout_paint]on section,font-sans text-6xl md:text-8xl font-black tracking-tighter leading-[0.92]on h2. The::before/::afterlayers need a custom plugin — Tailwind can't handlecontent: attr(data-text). Ship as a scoped CSS module.
Gotchas — read before shipping
- NEVER animate the
clip-pathpolygon values on the pseudo-elements — that triggers full paint on every keyframe and INP catapults past 500ms on mid-tier mobile. Animate onlytransformas this demo does; keep the clip-path static. Thesteps(2)jitter onhs-29-jitis safe because it toggles between two composited positions with no interpolation. - The
hs-29-blinkon the REC eyebrow flashes at 1.4s intervals — that's ABOVE the WCAG 2.3.1 seizure threshold (3 flashes per second), so this is safe. But if you speed it up to<0.35s, you cross into flash territory and fail 2.3.1. Verify with the PEAT (Photosensitive Epilepsy Analysis Tool) before shipping anything faster. - The static-noise overlay
.hs-29__staticusesrgba(255,255,255,0.04)— that's near-imperceptible on#1a1818(~1.05:1 contrast) but adds ~30% GPU paint cost on the animated jitter. If your INP budget is tight (targeting sub-150ms for Core Web Vitals green), drop the second radial-gradient layer and keep only the 3px grid — visually 90% identical. - The tape-blue CTA
#38b8d6on gray#1a1818contrast is ~6.4:1 — passes WCAG AA (1.4.3) for normal text but not AAA. The button text is#1a1818on#38b8d6, same 6.4:1. If your CTA copy is small caps below 13px, deepen the button color to#2a95b0or use pure white text — the current pairing is right at the AA limit. - In Safari 16 and older,
data-textattribute reading viacontent: attr(data-text)does NOT respect emoji or CJK characters in the attribute — the pseudo-element renders empty. Restrict the glitch text to Latin-1 characters, or shim with a<span aria-hidden="true">duplicate for non-Latin scripts. - The
prefers-reduced-motionguard disables the static, blink, and RGB-shift animations — but leaves the scanline overlay static, which is correct (constant patterns don't trigger vestibular response). WCAG 2.3.3 compliance is intact. However, if you add mouse-tracking glitch amplification (a common upgrade), guard THAT viamatchMediaor you fail vestibular safety.