Backgrounds✨ Premium

Chromatic Aberration Text

Two CSS ::before and ::after pseudo-elements duplicate the text via content: attr(data-text) and offset in opposite directions on hover, simulating the chromatic dispersion of a prism.

CSSHoverRGB Split

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Backgrounds has 50 effects, including 6 free. Explore the category →

3 usage examples

Hero headline — Portfolio or creative landing — Chromatic Aberration Text example 1

① Hero headline — Portfolio or creative landing

WhenA full-width display title on a dark background where users naturally mouse over before scrolling.
WhyThe effect is most striking on large typography (4–6 rem): the RGB channel offset covers a visible area and the shimmer reinforces the unstable signal feel without hurting readability.
Settingsfont-size 5 rem or more, increased offset (translate ±6px/±3px), short uppercase text (1–2 words).
Global navigation — Agency or design studio — Chromatic Aberration Text example 2

② Global navigation — Agency or design studio

WhenNavigation links on a dark site (agency, studio, portfolio) need subtle hover feedback without classic underline or link color.
WhyEach nav item has its own <code>.aberration-container</code> and works independently — the effect resets as soon as the mouse leaves, ideal for a minimalist menu.
Settingsfont-size 1.2–1.5 rem, normal offset (±4px/±2px), channel opacity reduced to 0.55 for restraint.
Main menu — Dark game interface — Chromatic Aberration Text example 3

③ Main menu — Dark game interface

WhenA game or dark app welcome screen with vertical options (Play, Settings, Scores) where retro-digital style fits the aesthetic.
WhyChannel colors (purple + neon green) easily replace red+cyan to match the game brand. The <code>aberrationFlicker</code> animation reinforces the CRT and glitch atmosphere.
Settingsfont-size 2.5–3 rem, ::before color: #a855f7 (purple), ::after color: #4ade80 (neon green), transition 0.2s for snappier response.

How it works

The effect relies on two CSS pseudo-elements (::before and ::after) that replicate the text using content: attr(data-text). The data-text attribute on .aberration-text must match the visible text exactly — this is the only markup requirement.

The pseudo-elements are positioned absolute with z-index: -1 (behind the white main text) and start at opacity: 0. On hover of the .aberration-container, CSS transitions move ::before (red) to translate(-4px, -2px) and ::after (cyan) to translate(4px, 2px) with an opacity of 0.7 — the two channels diverge in opposite directions, recreating the wavelength separation of an optical prism.

Simultaneously, an aberrationFlicker animation is applied to the main text via text-shadow: it alternates between slightly offset red and cyan shadows (plus a magenta touch #f0f on the final keyframe) at 0.15 s in alternate infinite mode. This rapid shimmer on the text edges creates the impression of an unstable video signal.

The JS file is empty — the effect is 100% CSS, zero dependencies. Entry/exit transitions (transform 0.3s, opacity 0.3s) ensure smooth appearance and disappearance. No requestAnimationFrame, no canvas, no library.

Accessibility

  • No prefers-reduced-motion in the code: the aberrationFlicker animation and CSS transitions run even when the OS requests reduced motion. Recommended addition: @media (prefers-reduced-motion: reduce) { .aberration-text { animation: none; } .aberration-text::before, .aberration-text::after { transition: none; } }
  • The ::before and ::after pseudo-elements expose content: attr(data-text) — some screen readers (NVDA, VoiceOver) announce the text up to three times. Workaround: add aria-hidden="true" to .aberration-text and an explicit aria-label on the parent container.
  • The effect is hover only — no keyboard interaction is exposed. If the text is a link or button, add :focus-visible with a visible focus style.
  • Main text contrast (white on dark background): ratio ≥ 7:1 in the default state. The red and cyan channels are purely decorative layers behind the white text and carry no independent content.
  • No aria-* attributes in the effect source code. Depending on context (heading, link, menu), add the appropriate ARIA role and label to the parent container.

Browser compatibility

CSS pseudo-elements, transitions, animations and content: attr() — universal support since Chrome 26 / Firefox 4 / Safari 6. Zero JS, zero dependencies.

Chrome 60+✓ Full
Firefox 60+✓ Full
Safari 12+✓ Full
Edge 79+✓ Full
Mobile iOS✓ No hover — default state only
Android Chrome✓ No hover — default state only

Without hover support (mobile, keyboard) or without CSS animations, the white text displays normally without RGB channels — no JS errors, content remains fully readable.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="aberration-container">
  <!-- data-text must match the visible text exactly -->
  <span class="aberration-text" data-text="Your text">Your text</span>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
data-text (HTML attribute) PRISM Text duplicated by pseudo-elements. Must match the span's visible text exactly — the only required markup configuration.
translate(-4px, -2px) on ::before hover -4px, -2px Red channel offset on hover. Increase (±6px, ±8px) for a stronger effect; decrease (±2px) for subtlety.
translate(4px, 2px) on ::after hover 4px, 2px Cyan channel offset in the opposite direction. Keep symmetric with ::before for balanced output.
opacity: 0.7 on hover pseudo-elements 0.7 Intensity of the visible RGB channels. Between 0.4 (subtle) and 1 (fully saturated). Applies to both ::before and ::after.
color: red / color: #0ff red / cyan Colors of the ::before and ::after channels. Replace with any contrasting pair — purple+green, orange+blue, etc.
transition: transform .3s, opacity .3s 0.3s Entry and exit duration of channels on hover. Reduce to 0.15s for snappiness, increase to 0.5s for a slow fade.
animation: .15s aberrationFlicker infinite 0.15s Shimmer speed during hover. 0.08s = aggressive glitch, 0.3s = soft vibration.
font-size: 2rem on .aberration-text 2rem Text size. The effect reads well from 1.5 rem up — below that, a 4px offset is barely noticeable.

FAQ

CSS ::before and ::after pseudo-elements cannot access their parent's text content directly. The property content: attr(data-text) reads the HTML attribute and copies it into the pseudo-element — the standard technique for duplicating text in pure CSS, without JS. The text must be identical in data-text and in the visible span content.
The effect is designed for short, single-line text. On multiple lines, the red and cyan channels offset globally (the entire pseudo-element translates), which still works but is less precise than a single line. For best results, prefer short uppercase titles, labels, or keywords. If text must wrap, test with small offsets (±2px).
The effect is 100% CSS — each <span class="aberration-text" data-text="Your text"> inside its own <div class="aberration-container"> works independently, without selector conflicts. No JS initialization, no unique ID required. Place as many instances as needed.