Skip to main content
NostalgiaPHP
Home
About
  • Components
  • Blink
  • Fetch
  • Slider
  • REST API
BlogDoxSearchContact
Admin
  • Sitemap
  • Robots
GitHub
  1. Home
  2. Blog
  3. Appear Animations
Oct 2, 2025

Appear Animations

Subtle scroll-based animations can make a page feel alive without pulling in a large library like GSAP. We can build a lightweight “appear” helper by combining:

  • IntersectionObserver → detect when elements enter the viewport.
  • CSS transitions → handle the actual fade/slide/scale animations.
  • A simple .is-visible toggle → applied once, no reflows.

This balances performance and user experience while respecting prefers-reduced-motion.


CSS

Instead of hardcoding hidden/visible styles globally, we can keep things safe: if the JavaScript never loads, elements remain visible. The script injects the CSS rules dynamically.

.appear {
  --appear-translate: 128px;

  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  will-change: opacity, transform;

  /* appeared */
  &.is-visible {
    opacity: 1;
    transform: none;
  }
}

/* Variants override the baseline transform */
.appear-up { 
  transform: translateY(var(--appear-translate)); 
}
.appear-down { 
  transform: translateY(calc(var(--appear-translate) * -1));
}
.appear-left { 
  transform: translateX(var(--appear-translate)); 
}
.appear-right { 
  transform: translateX(calc(var(--appear-translate) * -1)); 
}
.appear-scale { 
  transform: scale(0.95); 
}

JavaScript

The script observes .appear elements and applies .is-visible when they enter the viewport:

    // No IO support → reveal immediately (again: no hiding CSS injected).
const revealAllNow = () => {
    const show = () => {
        document
            .querySelectorAll('.appear')
            .forEach(el => el.classList.add('is-visible'))
    }
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', show, { once: true })
    } else {
        show()
    }
}

// Respect reduced motion → don't inject the hiding CSS; just reveal.
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
    revealAllNow()
} else if (!('IntersectionObserver' in window)) {
    // No IO support → reveal immediately (again: no hiding CSS injected).
    revealAllNow()
} else {
    // JS present → inject CSS (so elements can start hidden) and observe
    injectCSS()

    const onIntersect = entries => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                entry.target.classList.add('is-visible')
                io.unobserve(entry.target)
            }
        })
    }

    const io = new IntersectionObserver(onIntersect, { threshold: 0.2 })

    const start = () => {
        const targets = document.querySelectorAll('.appear')
        if (!targets.length) return
        targets.forEach(el => io.observe(el))
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', start, { once: true })
    } else {
        start()
    }
}

Usage

<!-- Include in <head> or template, etc. -->
<script defer src="/static/js/apps/appear.js"></script>

<h2 class="appear appear-up">Fade In Heading</h2>

<p class="appear appear-scale">This paragraph scales up slightly as it fades in.</p>

<div class="appear appear-left">Slide from left</div>
<div class="appear appear-right">Slide from right</div>

Progressive Enhancement

⚠️ JavaScript is required for this effect.
If the script doesn’t load, .appear elements will remain visible by default. The animations are a progressive enhancement — the page works fine without them.


✨ That’s all it takes: a sprinkle of CSS + IntersectionObserver for lightweight appear animations.


Tagged:

  • css
  • animation
  • intersectionobserver

Explore

Recent Items

  • You Might Not Want to Use NostalgiaPHP
    Oct 8, 2025
  • Understanding the Styles
    Oct 5, 2025
  • Appear Animations
    Oct 2, 2025
  • Nosty CLI — Your New Best Friend
    Sep 28, 2025
  • Introducing the NostalgiaPHP REST API
    Sep 27, 2025

Tags

  • animation (1)
  • api (1)
  • blink (1)
  • css (1)
  • intersectionobserver (1)
  • js (1)
  • json (1)
  • nostalgia (2)
  • php (3)
  • reactivity (1)
  • rest (1)
  • retro (3)
  • simplicity (3)
  • slank (1)
© 2025 NostalgiaPHP. All rights reserved. ⬆ Back to Top