data-anim

Anti-FOUC

FOUC (Flash of Unstyled Content) is when elements briefly appear in their final state before animations have a chance to run. data-anim solves this with a 3-layer defense system that other libraries lack.

What is FOUC?

When a page loads, there’s a brief moment between HTML rendering and JavaScript execution. During this gap, animated elements are visible in their final position, then “jump” to their start position when the animation library initializes.

Traditional library (AOS, etc):
  Page loads → Elements visible at final position → JS loads → Elements jump to start → Animate
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                        This is FOUC
data-anim:
  Page loads → Elements hidden by CSS → JS ready → Animate smoothly
               ^^^^^^^^^^^^^^^^^^^^^^
               No flash, no jump

The 3-Layer Defense

Layer 1: Synchronous Script

data-anim loads as a synchronous <script> tag in the <head>, not async or defer. This ensures the CSS is injected before the browser renders any content.

<!-- Correct: synchronous in <head> -->
<head>
  <script src="https://unpkg.com/data-anim@latest/dist/data-anim.js"></script>
</head>

<!-- Wrong: async/defer causes FOUC -->
<head>
  <script async src="data-anim.js"></script>
</head>

Layer 2: Inline Critical CSS

The script immediately injects a tiny CSS rule that hides all [data-anim] elements:

[data-anim] { opacity: 0; }

This happens before the browser’s first paint, so elements are never visible in their un-animated state.

Layer 3: Animation Keyframes

Each animation’s keyframes start from the hidden state (opacity: 0, transformed position) and animate to the final state. When the animation triggers, the element smoothly transitions from invisible to visible.

Timing Diagram

Browser Timeline:
─────────────────────────────────────────────────────>

1. HTML parsing begins
2. <script> encountered in <head>
   ├─ CSS injected: [data-anim] { opacity: 0 }     ← Layer 2
   └─ IntersectionObserver set up
3. First paint - elements with data-anim are hidden  ← No FOUC!
4. Element enters viewport
5. Animation plays: opacity 0 → 1 + transform        ← Layer 3

Why Sync Script?

Other libraries use async or defer to avoid blocking page render. But this creates a race condition where the page can paint before the library hides elements.

data-anim’s script is tiny (under 2KB), so the blocking time is negligible — typically under 5ms. This is a deliberate trade-off: 5ms of blocking time eliminates all FOUC.

Comparison with Other Libraries

Feature data-anim AOS Animate.css GSAP
Anti-FOUC built-in
No flash on load
Works without JS fallback
Zero config anti-FOUC

data-anim handles all of this automatically. No extra CSS needed.