16 CSS Fade In Animation Designs10 / 16

CSS + JSMIT licensed

Word-by-Word Split Fade

A headline is split word-by-word into spans via JavaScript, each assigned an animation-delay, creating a sequential typewriter-style word cascade with translateY spring bounce.

Published

Live Demo
Try it

The code

<div class="fi-10" id="fi-10-root">
  <div class="fi-10__output">
    <div class="fi-10__label" id="fi-10-label">Word-by-word fade</div>
    <div class="fi-10__text" id="fi-10-text">Words appear one by one creating a cinematic reading experience</div>
    <div class="fi-10__sub" id="fi-10-sub">JavaScript splits text into spans, staggering animation-delay per word index.</div>
    <div class="fi-10__replay" id="fi-10-replay">↺ Replay</div>
  </div>
</div>
.fi-10 {
  --bg: #0a0f0a;
  --green: #4ade80;
  --lime: #a3e635;
  --text: #f0fdf4;
  font-family: 'Plus Jakarta Sans',sans-serif;
  min-height: 320px;
  border-radius: 20px;
  display: grid;
  place-items: center;
  padding: 40px;
  overflow: hidden;
}

.fi-10 *,
.fi-10 *::before,
.fi-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.fi-10 ::selection {
  background: var(--green);
  color: #000;
}

.fi-10__output {
  text-align: center;
  max-width: 560px;
}

.fi-10__label {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 20px;
  opacity: 0;
  animation: fi-10-word-fade .5s ease forwards .1s;
}

.fi-10__text {
  font-size: clamp(1.4rem,3.5vw,2.2rem);
  font-weight: 800;
  line-height: 1.4;
  color: var(--text);
  margin-bottom: 24px;
}
/* JS injects spans; each span animates individually */

.fi-10__word {
  display: inline-block;
  margin-right: .3em;
  opacity: 0;
  transform: translateY(12px);
  animation: fi-10-word-up .5s cubic-bezier(.16,1,.3,1) forwards;
}

.fi-10__sub {
  font-size: .9rem;
  color: rgba(240,253,244,.45);
  line-height: 1.6;
  opacity: 0;
  animation: fi-10-word-fade .5s ease forwards;
}

.fi-10__replay {
  margin-top: 20px;
  display: inline-block;
  font-size: .75rem;
  font-weight: 600;
  color: var(--green);
  cursor: pointer;
  border: 1px solid rgba(74,222,128,.2);
  border-radius: 20px;
  padding: 6px 16px;
  background: rgba(74,222,128,.08);
  transition: background .2s;
}

.fi-10__replay:hover {
  background: rgba(74,222,128,.15);
}

@keyframes fi-10-word-up {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fi-10-word-fade {
  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fi-10 * {
    animation: none!important;
    opacity: 1!important;
    transform: none!important;
  }
}
(function(){
  const textEl = document.getElementById('fi-10-text');
  const subEl  = document.getElementById('fi-10-sub');
  const replay = document.getElementById('fi-10-replay');
  const BASE_DELAY = 0.3;
  const STEP = 0.09;

  function splitAndAnimate(el, startDelay){
    const words = el.textContent.trim().split(/\s+/);
    el.innerHTML = '';
    words.forEach((w,i)=>{
      const span = document.createElement('span');
      span.className='fi-10__word';
      span.textContent = w;
      span.style.animationDelay = (startDelay + i * STEP)+'s';
      el.appendChild(span);
    });
    return startDelay + words.length * STEP;
  }

  function run(){
    const subDelay = splitAndAnimate(textEl, BASE_DELAY);
    subEl.style.animationDelay = (subDelay + 0.1)+'s';
    subEl.style.animation='none';
    void subEl.offsetWidth;
    subEl.style.animation='fi-10-word-fade .5s ease forwards';
  }

  run();

  replay.addEventListener('click',()=>{
    // Reset and re-animate
    textEl.querySelectorAll('.fi-10__word').forEach(s=>{
      s.style.animation='none';
      void s.offsetWidth;
      s.style.animation='fi-10-word-up .5s cubic-bezier(.16,1,.3,1) forwards';
    });
    subEl.style.animation='none';
    void subEl.offsetWidth;
    subEl.style.animation='fi-10-word-fade .5s ease forwards';
  });
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Fade In Animation Design 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: Word-by-Word Split Fade
Source: https://codefronts.com/motion/css-fade-in-animation/word-by-word-split-fade/

A headline is split word-by-word into spans via JavaScript, each assigned an animation-delay, creating a sequential typewriter-style word cascade with translateY spring bounce.
## HTML
```html
<div class="fi-10" id="fi-10-root">
  <div class="fi-10__output">
    <div class="fi-10__label" id="fi-10-label">Word-by-word fade</div>
    <div class="fi-10__text" id="fi-10-text">Words appear one by one creating a cinematic reading experience</div>
    <div class="fi-10__sub" id="fi-10-sub">JavaScript splits text into spans, staggering animation-delay per word index.</div>
    <div class="fi-10__replay" id="fi-10-replay">↺ Replay</div>
  </div>
</div>
```
## CSS
```css
.fi-10 {
  --bg: #0a0f0a;
  --green: #4ade80;
  --lime: #a3e635;
  --text: #f0fdf4;
  font-family: 'Plus Jakarta Sans',sans-serif;
  min-height: 320px;
  border-radius: 20px;
  display: grid;
  place-items: center;
  padding: 40px;
  overflow: hidden;
}

.fi-10 *,
.fi-10 *::before,
.fi-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.fi-10 ::selection {
  background: var(--green);
  color: #000;
}

.fi-10__output {
  text-align: center;
  max-width: 560px;
}

.fi-10__label {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 20px;
  opacity: 0;
  animation: fi-10-word-fade .5s ease forwards .1s;
}

.fi-10__text {
  font-size: clamp(1.4rem,3.5vw,2.2rem);
  font-weight: 800;
  line-height: 1.4;
  color: var(--text);
  margin-bottom: 24px;
}
/* JS injects spans; each span animates individually */

.fi-10__word {
  display: inline-block;
  margin-right: .3em;
  opacity: 0;
  transform: translateY(12px);
  animation: fi-10-word-up .5s cubic-bezier(.16,1,.3,1) forwards;
}

.fi-10__sub {
  font-size: .9rem;
  color: rgba(240,253,244,.45);
  line-height: 1.6;
  opacity: 0;
  animation: fi-10-word-fade .5s ease forwards;
}

.fi-10__replay {
  margin-top: 20px;
  display: inline-block;
  font-size: .75rem;
  font-weight: 600;
  color: var(--green);
  cursor: pointer;
  border: 1px solid rgba(74,222,128,.2);
  border-radius: 20px;
  padding: 6px 16px;
  background: rgba(74,222,128,.08);
  transition: background .2s;
}

.fi-10__replay:hover {
  background: rgba(74,222,128,.15);
}

@keyframes fi-10-word-up {
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fi-10-word-fade {
  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .fi-10 * {
    animation: none!important;
    opacity: 1!important;
    transform: none!important;
  }
}
```

## JavaScript
```js
(function(){
  const textEl = document.getElementById('fi-10-text');
  const subEl  = document.getElementById('fi-10-sub');
  const replay = document.getElementById('fi-10-replay');
  const BASE_DELAY = 0.3;
  const STEP = 0.09;

  function splitAndAnimate(el, startDelay){
    const words = el.textContent.trim().split(/\s+/);
    el.innerHTML = '';
    words.forEach((w,i)=>{
      const span = document.createElement('span');
      span.className='fi-10__word';
      span.textContent = w;
      span.style.animationDelay = (startDelay + i * STEP)+'s';
      el.appendChild(span);
    });
    return startDelay + words.length * STEP;
  }

  function run(){
    const subDelay = splitAndAnimate(textEl, BASE_DELAY);
    subEl.style.animationDelay = (subDelay + 0.1)+'s';
    subEl.style.animation='none';
    void subEl.offsetWidth;
    subEl.style.animation='fi-10-word-fade .5s ease forwards';
  }

  run();

  replay.addEventListener('click',()=>{
    // Reset and re-animate
    textEl.querySelectorAll('.fi-10__word').forEach(s=>{
      s.style.animation='none';
      void s.offsetWidth;
      s.style.animation='fi-10-word-up .5s cubic-bezier(.16,1,.3,1) forwards';
    });
    subEl.style.animation='none';
    void subEl.offsetWidth;
    subEl.style.animation='fi-10-word-fade .5s ease forwards';
  });
})();
```

How this works

The JavaScript splitAndAnimate function reads the headline's text content, splits it on whitespace, and rebuilds the element as a sequence of span.fi-10__word elements. Each span gets an animation-delay of BASE_DELAY + index × STEP — 0.3s base, 0.09s per word — and the CSS keyframe fi-10-word-up moves them from translateY(12px) opacity:0 to resting position.

The subtitle carries a separate fade-only animation delayed until after the last word has appeared, so the two text regions sequence naturally. The replay handler iterates all word spans, forces a reflow with offsetWidth to flush the running animation, then reassigns the animation property — a clean restart without DOM rebuilding. Without JavaScript, the raw text remains visible as a static fallback.

Make it yours

  • Reduce STEP from 0.09 to 0.05s for faster word cascade — good for short headlines.
  • Change the keyframe to translateX(-16px → 0) for a horizontal word-slide instead of vertical drop.
  • Apply the same technique to a paragraph's sentences by splitting on . instead of whitespace.
  • Add a highlight colour to alternate words via nth-child CSS on .fi-10__word spans.

Gotchas — read before shipping

  • Splitting text into spans changes the DOM structure — any existing CSS targeting direct text nodes (e.g. first-line pseudo-element) will no longer match.
  • Long headlines with many words accumulate large total delays — cap the stagger at ~15 words to prevent the last word appearing after 1.5s+, which reads as a broken animation.
  • The offsetWidth trick to force reflow for animation restart works in all browsers but causes a synchronous layout — avoid calling it inside a rapid loop or animation frame.

Browser support

ChromeSafariFirefoxEdge
60+12+60+60+

DOM manipulation and animation restart pattern works in all modern browsers

Techniques used in this demo

Search CodeFronts

Loading…