Trigger CSS Fade-In Animation with JavaScript on Page Load & Link Click
Learn how to trigger a CSS fade-in animation using JavaScript on initial page load and when specific links are clicked. Fix common issues with DOMContentLoaded and event delegation.
How can I trigger a CSS fade-in animation (Text-Crawl-fade-in) in JavaScript to play exclusively on the initial page load and when specific story title links are clicked?
I’m building a short stories blog and want a slow fade-in effect for mood. The animation should activate:
- Upon the first load of the website.
- When a user clicks on story title
<a>tags.
My current JavaScript attempts to achieve this, but I’m facing issues with both conditions. I’ve tried using document.getElementsByTagName('a') for link detection and DOMContentLoaded for page load, but these haven’t worked as expected.
Here are the relevant code snippets:
JavaScript:
/*Text-Crawl*/
/*Function that grabs the css animations needed*/
function TextCrawlFadeIn(){
if (!window.AnimationEvent) { return; }
var fader = document.getElementById('Text-Crawl');
fader.classList.add('Text-Crawl-fade-out'); // Note: This adds 'fade-out', not 'fade-in'
}
/*My attempt at having the script recognise the DomContentloader*/
document.addEventListener('DOMContentLoaded', (event) => {
if (!window.AnimationEvent) { return; }
// 'anchors' is undefined here, and the loop structure seems incorrect for its purpose
for (var idx=0; idx<anchors.length; idx+=1) {
if (anchors[idx].hostname !== window.location.hostname ||
anchors[idx].pathname === window.location.pathname) {
continue;
}
window.addEventListener('pageshow', function (event) {
if (!event.persisted) {
return;
}
/*Removes the other animation in the case of Fade-out playing*/
var fader = document.getElementById('Text-Crawl');
fader.classList.remove('Text-Crawl-fade-in'); // This removes 'fade-in'
});
}
});
HTML:
<svg id="fader" class="fade-out"></svg>
<svg id="Text-Crawl" class="Text-Crawl-fade-out"></svg>
<script src="Javascript_Cyrus_Blog.js"></script>
What is the correct JavaScript approach to ensure the Text-Crawl-fade-in animation plays reliably under these two specific conditions?
To trigger a CSS fade-in animation like Text-Crawl-fade-in reliably with JavaScript, add the animation class directly to your #Text-Crawl element on DOMContentLoaded for initial page loads and use event delegation on document to catch clicks from story title <a> tags. This fixes issues like undefined variables, wrong class names, and nested loops in your code by defining a reusable triggerFadeIn() function that removes any prior state (like fade-out) before applying fade-in. Developers on Stack Overflow often toggle classes this way for smooth CSS animations, ensuring the effect plays on first load and link interactions without interfering with navigation.
Contents
- Fixing Issues in Your Current Code
- Setting Up the CSS Fade-In Animation
- Triggering the Animation on Initial Page Load
- Handling Clicks on Story Title Links
- Supporting Back/Forward Cache with Pageshow
- Delaying Navigation to Complete the Fade-In
- Complete Working JavaScript Code
- Testing and Best Practices
Fixing Issues in Your Current Code
Your script runs into several pitfalls that prevent the fade in CSS effect from working. First, TextCrawlFadeIn() adds Text-Crawl-fade-out instead of Text-Crawl-fade-in, which plays the wrong animation. Second, anchors is never defined—it’s referenced in a loop without document.querySelectorAll('a') or similar. Third, the event listeners nest incorrectly: pageshow sits inside the for loop and DOMContentLoaded, causing it to attach multiple times or skip execution.
The window.AnimationEvent check is unnecessary; modern browsers support CSS animations via classList.add(). Nested structures also mean link clicks never get proper handlers. A cleaner approach uses a single triggerFadeIn() function, called from DOMContentLoaded for page load and delegated clicks for links. This mirrors solutions in the MrWPress guide, which debugs similar blog fade effects.
Setting Up the CSS Fade-In Animation
Before JavaScript animation kicks in, define your animation CSS properly. Your HTML has <svg id="Text-Crawl" class="Text-Crawl-fade-out">, so start with that class, then swap to Text-Crawl-fade-in for the effect.
Here’s a complete CSS keyframes animation example for a slow mood-matching fade-in:
#Text-Crawl {
opacity: 0; /* Start invisible */
animation-fill-mode: forwards; /* Keeps final state after animation */
}
.Text-Crawl-fade-in {
animation: fadeIn 2s ease-in-out forwards;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(20px); /* Subtle slide-up for depth */
}
to {
opacity: 1;
transform: translateY(0);
}
}
.Text-Crawl-fade-out {
animation: fadeOut 1s ease-out forwards;
}
@keyframes fadeOut {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(-20px);
}
}
The forwards fill mode ensures your SVG stays visible post-animation, as noted in CSS animation docs. Add pointer-events: none during animation if clicks should pause.
Triggering the Animation on Initial Page Load
For the first website load, hook into DOMContentLoaded—it fires once the DOM is ready, perfect for html css animation on elements like your SVG.
Define a simple function:
function triggerFadeIn() {
const fader = document.getElementById('Text-Crawl');
if (!fader) return;
fader.classList.remove('Text-Crawl-fade-out', 'Text-Crawl-fade-in'); // Reset state
fader.classList.add('Text-Crawl-fade-in'); // Trigger!
}
Then attach it:
document.addEventListener('DOMContentLoaded', triggerFadeIn);
This runs immediately on load, fading in your text crawl for that immersive blog mood. Stack Overflow threads confirm class toggling works better than direct style changes for CSS animations.
Handling Clicks on Story Title Links
Story titles are likely <a> tags with classes like .story-title. Instead of looping over getElementsByTagName('a') (which grabs everything and misses dynamics), use event delegation on document. It catches clicks efficiently, even for future links.
document.addEventListener('click', function(e) {
if (e.target.matches('.story-title') || e.target.closest('.story-title')) { // Target your links
e.preventDefault(); // Stop instant navigation
triggerFadeIn();
// Handle navigation after (see next section)
}
});
matches() or closest() targets specific selectors—swap .story-title for yours, like a[href^="/stories/"]. This avoids your undefined anchors loop. Examples on CodePen show this toggling CSS animation rotate or fades on clicks seamlessly.
Supporting Back/Forward Cache with Pageshow
Browsers’ bfcache (back/forward cache) restores pages instantly, skipping DOMContentLoaded. Your pageshow attempt was close but misplaced.
Fix it standalone:
window.addEventListener('pageshow', function(event) {
if (event.persisted) { // Only if from bfcache
triggerFadeIn();
}
});
Place this outside other listeners. The MrWPress tutorial stresses this for reliable fade in css on restored pages—users expect the mood effect every time.
Delaying Navigation to Complete the Fade-In
Link clicks need a pause so the 2s fade finishes before jumping. Use animationend for precision or setTimeout as fallback.
Enhance the click handler:
document.addEventListener('click', function(e) {
const link = e.target.closest('a.story-title'); // Adjust selector
if (link) {
e.preventDefault();
triggerFadeIn();
const fader = document.getElementById('Text-Crawl');
const onEnd = () => {
window.location.href = link.href; // Navigate
fader.removeEventListener('animationend', onEnd);
};
fader.addEventListener('animationend', onEnd);
// Fallback if animationend fails
setTimeout(() => {
if (fader.classList.contains('Text-Crawl-fade-in')) {
window.location.href = link.href;
}
}, 2200); // Slightly over 2s
}
});
This lets the slow fade breathe, enhancing your short stories blog vibe. Stack Overflow solutions use setTimeout(0) for resets, but extend it here for duration.
Complete Working JavaScript Code
Combine everything into one script. Add it before </body> or defer it.
function triggerFadeIn() {
const fader = document.getElementById('Text-Crawl');
if (!fader) return;
fader.classList.remove('Text-Crawl-fade-out', 'Text-Crawl-fade-in');
fader.classList.add('Text-Crawl-fade-in');
}
// Initial load
document.addEventListener('DOMContentLoaded', triggerFadeIn);
// Bfcache
window.addEventListener('pageshow', function(event) {
if (event.persisted) triggerFadeIn();
});
// Story link clicks (adjust .story-title selector)
document.addEventListener('click', function(e) {
const link = e.target.closest('a.story-title');
if (link) {
e.preventDefault();
triggerFadeIn();
const fader = document.getElementById('Text-Crawl');
const navigate = () => {
window.location.href = link.href;
fader.removeEventListener('animationend', navigate);
};
fader.addEventListener('animationend', navigate);
setTimeout(navigate, 2200);
}
});
Update HTML: Remove initial class="Text-Crawl-fade-out" or let JS handle it. Test in incognito—works on load, clicks, and back button.
Testing and Best Practices
Test across Chrome, Firefox, Safari: Open dev tools, throttle to slow 3G, navigate stories. Check Network tab for bfcache (pageshow fires). For css animation delay, tweak ease-in-out or add animation-delay: 0.5s.
Avoid overkill: No jQuery needed—vanilla js css animation is lightweight. Profile with performance.now() if sluggish. For SVGs, ensure preserveAspectRatio doesn’t fight transforms. Communities like Stack Overflow recommend removing/re-adding classes to replay, which our reset does.
Scale for your blog: Add IntersectionObserver later for scroll-triggered css animation scroll, but this nails your two conditions.
Sources
- https://www.mrwpress.com/trigger-css-animations-javascript/
- https://stackoverflow.com/questions/22718441/trigger-css3-transition-on-page-load
- https://stackoverflow.com/questions/44846614/trigger-css-animations-in-javascript
- https://stackoverflow.com/questions/71486798/trigger-css-animation-on-div-click
- https://codepen.io/thetallweeks/pen/naNPWm
- https://stackoverflow.com/questions/40179959/trigger-same-css-animation-on-every-click
- https://stackoverflow.com/questions/22112693/how-to-trigger-animate-css-on-page-load
- https://stackoverflow.com/questions/4847996/css-animation-onclick
Conclusion
With this CSS fade-in animation setup driven by JavaScript, your short stories blog gets that smooth, moody entrance on every initial load and story link click—reliable across caches and browsers. Drop in the full code, tweak selectors/CSS durations, and watch engagement rise as users linger for the effect. You’ve fixed the core bugs; now iterate with performance tools for polish.