Introduction to Text Splitting
Text splitting is a fundamental technique for creating advanced text animations. The principle is simple: break text down into individual elements (letters, words, or lines) to animate them independently.
This technique is used by the greatest websites and creative agencies to create memorable experiences. From titles that reveal letter by letter to spectacular glitch effects, the possibilities are endless.
Animating an entire text only allows global transformations (fade, slide). By splitting the text, each character becomes an individually animatable element, opening the door to much richer effects.
In this complete guide, we will explore 6 different techniques of text splitting and animation, from the simplest to the most elaborate. Each example includes the complete code, ready to copy.
Split by letters with JavaScript
The first step is to create a function that will break our text into individual characters. Each letter will be wrapped in a <span> to be animated.
function splitByChars(element) {
// Save the original text
const text = element.textContent;
// Clear the element
element.innerHTML = '';
// Split each character
text.split('').forEach((char, index) => {
const span = document.createElement('span');
span.className = 'char';
// Space handling (uses non-breaking space)
span.textContent = char === ' ' ? '\u00A0' : char;
// Progressive delay for animation
span.style.animationDelay = `${index * 0.05}s`;
element.appendChild(span);
});
return element;
}
// Utilisation
const title = document.querySelector('.my-title');
splitByChars(title);
Key implementation points
- Non-breaking spaces: Normal spaces would be ignored by the browser. We use
\u00A0to preserve them. - Animation delay: Each character receives a progressive delay (0.05s by default) to create the cascade effect.
- .char class: Allows targeting all characters in CSS for animation.
Split by words
Sometimes, animating word by word is more suitable, particularly for long sentences or headings. The principle is similar, but splitting on spaces.
function splitByWords(element) {
const text = element.textContent;
const words = text.split(' ');
element.innerHTML = '';
words.forEach((word, index) => {
const span = document.createElement('span');
span.className = 'word';
span.textContent = word;
span.style.animationDelay = `${index * 0.15}s`;
element.appendChild(span);
});
}
// CSS associe
/*
.word {
display: inline-block;
margin: 0 8px;
opacity: 0;
transform: translateY(20px) rotateX(-90deg);
}
.animate .word {
animation: wordReveal 0.6s forwards;
}
@keyframes wordReveal {
to {
opacity: 1;
transform: translateY(0) rotateX(0);
}
}
*/
Letter-by-letter animations
Once the text is split, different types of animations can be applied. Here are the 4 most popular animations with their interactive demos.
Fade In Stagger
The most classic animation: each letter appears progressively with a fade.
Slide Up
The letters appear rising from the bottom, creating a dynamic reveal effect.
Wave Effect
A looping animation where the letters ripple like a wave. Perfect for attracting attention.
Scale Pop
Each letter appears with a zoom effect, as if it "pops" onto the screen.
/* Base: each character is invisible by default */
.split-text .char {
display: inline-block;
opacity: 0;
}
/* 1. Fade In */
.split-text.animate-fade .char {
animation: charFadeIn 0.5s forwards;
}
@keyframes charFadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* 2. Slide Up */
.split-text.animate-slide .char {
animation: charSlideUp 0.5s forwards;
}
@keyframes charSlideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* 3. Wave (continuous animation) */
.split-text.animate-wave .char {
opacity: 1;
animation: charWave 1.5s ease-in-out infinite;
}
@keyframes charWave {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-15px); }
}
/* 4. Scale Pop */
.split-text.animate-scale .char {
animation: charScale 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}
@keyframes charScale {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}
Scramble / Shuffle Effect
The scramble (or shuffle) effect is one of the most impressive: the text displays random characters that progressively stabilize to reveal the final text. It is the quintessential "hacker" effect.
class ScrambleText {
constructor(element, options = {}) {
this.element = element;
this.chars = options.chars || '!@#$%^&*()_+-=[]{}|;:,.<>?';
this.duration = options.duration || 2000;
this.originalText = element.textContent;
}
scramble(newText) {
const target = newText || this.originalText;
const length = target.length;
const startTime = Date.now();
const animate = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / this.duration, 1);
// Number of revealed characters
const revealed = Math.floor(progress * length);
let result = '';
for (let i = 0; i < length; i++) {
if (i < revealed) {
// Caractere final
result += target[i];
} else if (target[i] === ' ') {
// Preserve spaces
result += ' ';
} else {
// Caractere aleatoire
result += this.chars[Math.floor(
Math.random() * this.chars.length
)];
}
}
this.element.textContent = result;
if (progress < 1) {
requestAnimationFrame(animate);
}
};
animate();
}
}
// Utilisation
const scrambler = new ScrambleText(
document.querySelector('.scramble-text'),
{ duration: 2000 }
);
scrambler.scramble('ACCESS GRANTED');
The scramble effect updates the DOM every frame. For long character strings, consider limiting the framerate or using textContent instead of innerHTML for better performance.
Advanced Typewriter effect
The typewriter effect is a timeless classic. Here is an advanced implementation with a blinking cursor, deletion support, and the ability to chain multiple texts.
class Typewriter {
constructor(element, options = {}) {
this.element = element;
this.typeSpeed = options.typeSpeed || 100;
this.deleteSpeed = options.deleteSpeed || 50;
this.pauseTime = options.pauseTime || 2000;
this.texts = options.texts || [];
this.loop = options.loop !== undefined ? options.loop : true;
this.currentIndex = 0;
this.isRunning = false;
}
async type(text) {
for (let i = 0; i <= text.length; i++) {
this.element.textContent = text.slice(0, i);
await this.sleep(this.typeSpeed);
}
}
async delete(text) {
for (let i = text.length; i >= 0; i--) {
this.element.textContent = text.slice(0, i);
await this.sleep(this.deleteSpeed);
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async start() {
this.isRunning = true;
while (this.isRunning) {
const text = this.texts[this.currentIndex];
await this.type(text);
await this.sleep(this.pauseTime);
await this.delete(text);
await this.sleep(500);
this.currentIndex = (this.currentIndex + 1) % this.texts.length;
if (!this.loop && this.currentIndex === 0) break;
}
}
stop() {
this.isRunning = false;
}
}
// Utilisation
const typewriter = new Typewriter(
document.querySelector('.typewriter-text'),
{
texts: ['Developer', 'Designer', 'Creator'],
typeSpeed: 80,
deleteSpeed: 40,
pauseTime: 1500
}
);
typewriter.start();
Recommended libraries
If you don't want to code these effects yourself, several excellent libraries can save you time.
| Library | Size | Split | Animations | Note |
|---|---|---|---|---|
| SplitType | ~5KB | Via CSS/GSAP | Most popular | |
| GSAP SplitText | ~10KB | Premium, most powerful | ||
| Splitting.js | ~2KB | Via CSS | Ultra-leger | |
| Typed.js | ~5KB | Typewriter only | Specialise typewriter |
Example with SplitType
// Installation: npm install split-type
import SplitType from 'split-type';
// Split text into characters
const text = new SplitType('.my-title', {
types: 'chars, words',
tagName: 'span'
});
// Access the elements
console.log(text.chars); // Array of character s
console.log(text.words); // Array of word s
// With GSAP for animation
gsap.from(text.chars, {
opacity: 0,
y: 20,
stagger: 0.05,
duration: 0.5,
ease: 'power2.out'
});
Check out the SplitType documentation for more advanced options like line splitting or style preservation.
Best practices
Before deploying your text animations in production, keep these tips in mind.
Performance
- Use
transformandopacityfor animations - these properties are GPU-optimized - Avoid animating too many elements simultaneously - more than 50 characters can slow down mobile devices
- Use
will-changesparingly on animated elements
Accessibility
- Respect
prefers-reduced-motionfor motion-sensitive users - Do not block reading - the final text must be visible quickly
- Keep the text accessible to screen readers
/* Disable animations if user prefers */
@media (prefers-reduced-motion: reduce) {
.split-text .char,
.word-split .word {
animation: none !important;
opacity: 1 !important;
transform: none !important;
}
}
SEO
- Text must be present in the initial HTML, not generated only by JS
- Avoid replacing text with images or canvas
- Spans do not affect SEO as long as the text content is preserved
Conclusion
Text splitting is a powerful technique that opens the door to spectacular text animations. Whether you choose to implement your own solution or use a library, the possibilities are endless.
We have covered the essential techniques:
- Split by characters for letter-by-letter animations
- Split by words for smoother reveals
- CSS animations: fade, slide, wave, scale
- Scramble effect for a "hacker" look
- Typewriter for the typewriter effect
Do not hesitate to combine these techniques and experiment. The best animations are often those that surprise while remaining subtle.
Discover our effects library for ready-to-use text animations, with one-click copyable code.