
How to Use Kinetic Typography Without Overwhelming Users?
- Sajjad
- Typography
- 01 Oct, 2026
A product launch page opens with a headline that types itself out letter by letter, then every section heading slides up and fades in as you scroll, the stats count up from zero, and a marquee of customer names streams across the footer. The first visit feels exciting. The second visit, when you just want the pricing, feels like waiting in line. For a visitor with a vestibular disorder, the sliding and scrolling may cause nausea. For a screen reader user, the typewriter headline may be announced as a stream of single letters. Kinetic typography is powerful, and that is exactly why it needs discipline.
This article explains what kinetic typography is, where it actually helps, and how to build it so it doesn't get in the way. You'll get CSS and JavaScript patterns for reveals, scroll-driven effects, variable font motion, and text splitting, along with the accessibility rules from WCAG, the prefers-reduced-motion media query, and the performance techniques that keep animated text smooth.
What Is Kinetic Typography?
Kinetic typography is text that moves or changes over time: position, scale, opacity, weight, width, color, or the letters themselves. The term comes from film title sequences and motion graphics, where animated type sets mood and pace. On the web it ranges from subtle to dramatic:
| Type of motion | Example | Intensity |
|---|---|---|
| State transition | A link's weight increases slightly on hover | Low |
| Entrance reveal | A headline fades and rises into place once on load | Low–medium |
| Scroll-linked | Words fill with color as you scroll through a section | Medium |
| Variable axis motion | A headline's weight or width breathes continuously | Medium–high |
| Per-letter effects | Letters cascade, scramble, or bounce individually | High |
| Continuous loops | Marquees, rotating words, infinite tickers | High |
The intensity column matters. Low-intensity motion supports reading; high-intensity motion competes with it.
When Kinetic Type Helps and When It Hurts
Motion attracts attention automatically. Peripheral vision is highly sensitive to movement, which is why animated text is so effective at pulling the eye, and so exhausting when overused.
Kinetic type helps when it:
- Draws attention to one primary message, such as a hero headline or a key statistic.
- Shows a relationship or change, like a number updating or a word swapping to illustrate options.
- Gives feedback on interaction, such as a button label changing state.
- Establishes brand personality in a single, deliberate moment.
It hurts when it:
- Applies to body text or anything the user needs to read carefully.
- Delays access to content, forcing users to wait for an animation to finish.
- Runs continuously next to text people are trying to read.
- Repeats on every scroll or every visit.
- Moves large areas of the screen, which is the main trigger for vestibular discomfort.
A useful rule: one kinetic moment per view. If everything moves, nothing stands out, and the page feels noisy.
Accessibility Rules You Must Follow
Several WCAG success criteria apply directly to animated text.
- 2.2.2 Pause, Stop, Hide (Level A). Any moving, blinking, or scrolling content that starts automatically, lasts more than five seconds, and appears alongside other content must have a mechanism to pause, stop, or hide it. Marquees and looping tickers fall under this.
- 2.3.1 Three Flashes or Below Threshold (Level A). Nothing may flash more than three times in any one-second period. Rapid color flicker in text effects can fail this.
- 2.3.3 Animation from Interactions (Level AAA). Motion triggered by interaction, such as scroll-linked parallax, can be disabled unless it's essential. Even though it's AAA, it's the criterion that
prefers-reduced-motionsupport is built around. - 1.4.3 Contrast (Minimum). Text must meet 4.5:1 throughout the animation if it's readable at that point. Text fading in from low opacity is fine; text that sits at low contrast for extended periods is not.
Respect prefers-reduced-motion
Users can ask their operating system to reduce motion, and browsers expose that preference. The safest pattern is to make motion opt-in: write the static design first, then add animation only for users who haven't asked for less.
.headline {
opacity: 1;
}
@media (prefers-reduced-motion: no-preference) {
.headline {
animation: rise 600ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
}
@keyframes rise {
from {
opacity: 0;
translate: 0 0.5em;
}
}
Reduced motion doesn't have to mean no motion. A simple opacity fade is generally fine, because it doesn't involve movement across the screen. Swap large movements for fades rather than removing every transition.
In JavaScript, read the same preference before starting animations:
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (!prefersReducedMotion) {
startHeadlineAnimation();
}
Keep Text Readable to Assistive Technology
Effects that split text into individual letters or words can wreck screen reader output. If you wrap each letter in a span, some screen readers announce letters one at a time. Keep the real text available and hide the visual pieces:
<h1 class="split" aria-label="Design that moves">
<span aria-hidden="true">
<span class="char">D</span><span class="char">e</span>...
</span>
</h1>
Using aria-label on a heading works in practice, but a more robust pattern is a visually hidden copy of the text plus an aria-hidden animated version, because aria-label support on non-interactive elements can vary.
Typewriter effects have an extra problem: the text isn't in the DOM until it's typed. Put the full text in the markup and animate its visibility with CSS, rather than appending characters with JavaScript.
Build Entrance Reveals With CSS
Most kinetic headlines need nothing more than CSS. A staggered word reveal is a good example:
<h1 class="reveal-words">
<span style="--i: 0">Type</span>
<span style="--i: 1">that</span>
<span style="--i: 2">moves</span>
</h1>
.reveal-words span {
display: inline-block;
}
@media (prefers-reduced-motion: no-preference) {
.reveal-words span {
animation: rise 500ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
animation-delay: calc(var(--i) * 80ms);
}
}
Keep it short. Total sequences longer than about one second start to feel like waiting. Animate only opacity, transform, translate, scale, and rotate where possible, because the browser can run them on the compositor without recalculating layout.
Avoid Layout Shift
An entrance animation that changes a heading's size or pushes content around adds to Cumulative Layout Shift. Transforms don't affect layout, so a heading that rises with translate keeps its space reserved from the first frame. Never animate font-size, margin, or height for reveals.
Scroll-Driven Kinetic Type
CSS scroll-driven animations let you tie text effects to scroll position without JavaScript scroll listeners. They're supported in Chromium-based browsers and Safari, and the pattern degrades cleanly elsewhere.
A popular effect fills words with color as a section scrolls into view:
.scroll-fill {
--ink: #1a1a1a;
color: color-mix(in oklab, var(--ink) 25%, transparent);
background: linear-gradient(var(--ink), var(--ink)) no-repeat;
background-size: 0% 100%;
background-clip: text;
-webkit-background-clip: text;
}
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.scroll-fill {
animation: fill linear both;
animation-timeline: view();
animation-range: entry 20% cover 60%;
}
}
}
@keyframes fill {
to {
background-size: 100% 100%;
}
}
Two caveats. First, check that the unfilled state still has readable contrast, or provide a fully filled default for browsers without support and reduced-motion users. Second, keep scroll-linked effects to short display passages. Applying them to paragraphs forces readers to scroll at the animation's pace.
Animate Variable Font Axes
Variable fonts open up motion that's purely typographic: weight that grows on hover, width that stretches, slant that shifts. Detailed techniques are in how to animate variable fonts; here's the responsible baseline:
.nav a {
font-weight: 450;
transition: font-weight 200ms ease-out;
}
.nav a:hover,
.nav a:focus-visible {
font-weight: 650;
}
Watch for reflow. Weight changes alter glyph widths in most fonts, which means neighboring text shifts. For navigation and buttons, either choose a font with a grade axis (GRAD), which changes stroke thickness without changing width, or reserve space for the widest state:
.button {
font-variation-settings: "GRAD" 0;
transition: font-variation-settings 200ms ease-out;
}
.button:hover {
font-variation-settings: "GRAD" 150;
}
Animating font-weight or font-variation-settings triggers text re-rendering on every frame, which is more expensive than a transform. Keep these animations short and limit them to small amounts of text.
Splitting Text With JavaScript
For per-letter effects you need individual elements. Do the splitting once, keep the original text accessible, and use the Web Animations API or a library like GSAP or Motion for orchestration.
function splitText(el: HTMLElement) {
const text = el.textContent ?? "";
el.setAttribute("aria-label", text);
const wrapper = document.createElement("span");
wrapper.setAttribute("aria-hidden", "true");
const segmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
for (const { segment } of segmenter.segment(text)) {
const span = document.createElement("span");
span.className = "char";
span.textContent = segment;
wrapper.append(span);
}
el.replaceChildren(wrapper);
return wrapper.querySelectorAll<HTMLSpanElement>(".char");
}
const heading = document.querySelector<HTMLElement>(".split");
const reduce = matchMedia("(prefers-reduced-motion: reduce)").matches;
if (heading && !reduce) {
splitText(heading).forEach((char, i) => {
char.style.display = "inline-block";
char.animate(
[
{ opacity: 0, transform: "translateY(0.4em)" },
{ opacity: 1, transform: "none" },
],
{ duration: 400, delay: i * 25, easing: "ease-out", fill: "both" }
);
});
}
Intl.Segmenter splits by grapheme, so emoji, accented letters, and complex scripts stay intact. Splitting with split("") breaks characters made of multiple code points.
Splitting also disables kerning and ligatures between letters, because each one is in its own box. Remove the spans after the animation finishes, restoring plain text, if the heading stays on screen.
Loops, Marquees, and Rotating Words
Continuous motion is the riskiest category. If you use it:
- Provide a pause control to meet WCAG 2.2.2 when it runs longer than five seconds.
- Pause on hover and focus so people can read it.
- Stop it entirely under reduced motion.
- Keep the content available statically, for example as a list that the marquee duplicates visually.
.marquee-track {
display: flex;
gap: 3rem;
}
@media (prefers-reduced-motion: no-preference) {
.marquee-track {
animation: marquee 30s linear infinite;
}
.marquee:hover .marquee-track,
.marquee:focus-within .marquee-track,
.marquee[data-paused] .marquee-track {
animation-play-state: paused;
}
}
@keyframes marquee {
to {
translate: -50% 0;
}
}
Pair the data-paused attribute with a visible pause button that toggles it.
A Checklist for Kinetic Typography
Before shipping, check each animated text element against this list:
- Does it serve one clear purpose?
- Is the content fully readable without the animation?
- Is the motion gated behind
prefers-reduced-motion: no-preference? - Does it finish in under about one second, or can it be paused if it loops?
- Does it avoid flashing more than three times per second?
- Is the text accessible as whole words to screen readers?
- Does it animate transforms and opacity rather than layout properties?
- Does it stay smooth on a mid-range phone with CPU throttling in DevTools?
The broader context of how motion fits into modern design is covered in typography trends shaping web design in 2026, and the user-experience impact in how typography affects UX and conversions.
Kinetic Typography FAQ
Not inherently. It becomes a problem when motion is large, continuous, or unavoidable. Gate animations behind prefers-reduced-motion, keep text readable as whole words, offer pause controls for loops, and never flash more than three times per second.
Not necessarily. Reduced motion means avoiding movement that can trigger vestibular symptoms, such as sliding, zooming, and parallax. Gentle opacity fades and color changes are generally acceptable replacements.
Avoid it. Body text needs to be read steadily, and motion breaks concentration. Limit kinetic effects to headlines, short statements, statistics, and interactive feedback.
Usually not. CSS animations, transitions, and scroll-driven animations handle most effects. Libraries help with complex per-letter sequencing and timeline orchestration, but the Web Animations API covers a lot of that natively.
They can. Animating layout properties like font-size or margin causes layout shift, and heavy JavaScript can delay interaction responsiveness. Animate transforms and opacity, reserve space for text from the first frame, and keep scripts small.
Keep the full text available as a single string, either with a visually hidden copy or an aria-label, and hide the individual animated letters with aria-hidden. This prevents screen readers from announcing letters one by one.
Conclusion
Kinetic typography works best as punctuation, not as prose. One well-timed headline reveal, a number that updates smoothly, or a weight shift on hover adds energy and clarity. Animating everything, looping constantly, or forcing users to wait does the opposite, and can make your site physically uncomfortable for some visitors.
Build motion as an enhancement on top of a complete static design, gate it behind prefers-reduced-motion, keep text accessible as whole words, stick to compositor-friendly properties, and give users control over anything that loops. Do that, and your type can move without overwhelming the people trying to read it.
Here are some useful references for going deeper on kinetic typography and accessible motion:
- MDN Web Docs: prefers-reduced-motion — detecting and respecting the user's motion preference.
- MDN Web Docs: CSS scroll-driven animations — scroll and view timelines for animation.
- W3C: Understanding Success Criterion 2.2.2: Pause, Stop, Hide — requirements for moving and auto-updating content.
- W3C: Understanding Success Criterion 2.3.3: Animation from Interactions — guidance on interaction-triggered motion.
- web.dev: prefers-reduced-motion: Sometimes less movement is more — practical patterns for reduced motion.


