Kinetic Typography
Pure CSS animation — each letter alternates weight, color and vertical offset with a 0.2s per-character stagger. Zero JavaScript.
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. Text has 56 effects, including 4 free. Explore the category →
3 usage examples



How it works
The text is split into <span class="vf-kinetic-char"> elements placed inside a .vf-kinetic-line set to display:flex. Each span receives a growing animation-delay (0s, 0.2s, 0.4s…) as an inline style attribute — that offset is what creates the letter-by-letter stagger, with no JavaScript involved.
The vfKinetic keyframe cycles through four states every 3s (ease-in-out, infinite), varying three CSS properties simultaneously: font-weight (800 → 300 → 900 → 400), color (#8b5cf6 → #ec4899 → #06b6d4 → #f59e0b), and transform (translateY ±8px + scaleY 0.9–1.2). Because each letter starts at a different phase, the eye reads controlled chaos while every individual animation remains perfectly regular.
font-weight interpolation is only smooth with a variable font that supports the wght axis. Inter (used by default) satisfies this requirement. With a non-variable font, the browser snaps to available weights (400, 700…) instead of interpolating.
The overflow: hidden on .vf-kinetic-line prevents letters from spilling vertically during the scaleY(1.2) peak — disable it if the container has a fixed height and you want the effect to breathe beyond the bounds.
Accessibility
- prefers-reduced-motion not present in the code: animations run unconditionally. To respect the OS preference, add
@media (prefers-reduced-motion: reduce) { .vf-kinetic-char { animation: none; } }. - The
<span>elements are native text — screen readers read the whole word without disruption; the animation is transparent to them. - No focusable element in the structure: no keyboard trap.
- Color variation carries no semantic information; the text remains readable in all keyframe states.
- WCAG AA contrast verified on dark background (#0a0a0f): purple #8b5cf6 (≈4.9:1), pink #ec4899 (≈5.9:1), cyan #06b6d4 (≈8.6:1), amber #f59e0b (≈9.8:1) — all pass for large text (≥18pt).
Browser compatibility
Pure CSS, zero dependencies. font-weight animation requires a variable font (wght axis) for smooth interpolation.
Without CSS animation support, letters display with their base style (weight 800, color #8b5cf6). No JS error, text remains readable.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="vf-kinetic-scene">
<div class="vf-kinetic-line" id="vfKineticText">
<span class="vf-kinetic-char" style="animation-delay:0s">K</span>
<span class="vf-kinetic-char" style="animation-delay:0.2s">I</span>
<span class="vf-kinetic-char" style="animation-delay:0.4s">N</span>
<!-- … one <span> per letter … -->
</div>
<span class="vf-kinetic-sub">weight + transform + color</span>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| animation-duration (on .vf-kinetic-char) | 3s | Duration of one full cycle. 1.5s = fast and nervous, 5s = slow and contemplative. |
| animation-delay (inline per span) | 0, 0.2s, 0.4s… | Stagger between letters. Drop to 0.08s for a near-simultaneous effect; increase to 0.4s for a slow wave. |
| font-size (on .vf-kinetic-char) | 2.2rem | Letter size. 1.4rem for a subtle label, 5rem for a full-screen hero title. |
| font-family (on .vf-kinetic-char) | Inter | Font family. Must be a variable font (wght axis) for smooth interpolation — Inter, Plus Jakarta Sans, DM Sans, Manrope. |
| Colors in @keyframes vfKinetic (0%, 25%, 50%, 75%) | #8b5cf6, #ec4899, #06b6d4, #f59e0b | The 4 colors letters cycle through. Align with your brand palette. |
| font-weight in @keyframes vfKinetic | 800, 300, 900, 400 | The 4 alternating weights (100–900, multiples of 100). Narrow the gap (e.g. 500–700) for a subtler effect. |
| translateY in @keyframes vfKinetic | 0, -8px, 0, 4px | Vertical shift per letter. ±16px for more bounce, ±2px for a barely-there effect. |
| scaleY in @keyframes vfKinetic | 1, 1.2, 0.9, 1.1 | Vertical stretch. Set scaleY to 1 at all stops to disable distortion and keep only weight + color. |
FAQ
Array.from(el.textContent).forEach((c,i) => { const s = document.createElement('span'); s.className = 'vf-kinetic-char'; s.style.animationDelay = i * 0.2 + 's'; s.textContent = c; el.appendChild(s); }); — clear the container first (el.innerHTML = ''), then run this loop.font-weight interpolation is only smooth with a variable font (wght axis). Without one, the browser snaps to available weights (400, 700…). Load Inter with font-weight: 100 900 via Google Fonts or self-host a variable font to restore smooth transitions.animation-play-state: document.querySelectorAll('.vf-kinetic-char').forEach(s => s.style.animationPlayState = 'paused') to freeze, replace with 'running' to resume. No other changes needed.