Context: I have a subtitle "About me" that animates with the library animejs as soon as it comes into view in the screen (every time). You can find the animation here, i got it from Tobia's Moving Letters.
The problem: As I scroll down to the subtitle, I'm able to see it right before the animation plays. So in other words: I scroll down, I read the subtitle "About me" and then it disappears just to have the letter pop in one by one.
This isn't want, I am looking for a way to have the initial text "About me" hidden and then have each animated letter appear
I made a snippet with the subtitle under some dummy text so it can be scrolled into.
// Wrap every letter in a span
var textWrapper = document.querySelector('.subtitle .ml6 .letters');
textWrapper.innerHTML = textWrapper.textContent.replace(/\S/g, "<span class='letter'>$&</span>");
const subtitle_animation = anime({
targets: '.subtitle .ml6 .letter',
translateY: ["1.1em", 0],
translateZ: 0,
duration: 750,
delay: (el, i) => 100 * i + 500
})
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
const aboutme = document.getElementById('about-me');
let aboutme_vis = false
let ready_to_play = true
document.addEventListener('scroll', function () {
isInViewport(aboutme) ? aboutme_vis = true : aboutme_vis = false;
if (aboutme_vis && ready_to_play) {
subtitle_animation.restart();
ready_to_play = false
}
if (!aboutme_vis){
ready_to_play = true
}
});
/* Subtitle Animation */
.subtitle .ml6 {
position: relative;
font-size: 1em;
}
.ml6 .text-wrapper-subtitle {
position: relative;
display: inline-block;
padding-right: 10%;
overflow: hidden;
}
.ml6 .letter {
display: inline-block;
line-height: 1em;
transform-origin: 0 0;
}
<div class="">
<h1>Title</h1>
<p>The subtitle About me can be found below! </p>
<h2>Random text so its possible to scroll: </h2>
<p>
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
<p>
<p>
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
<p>
<p>
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
<p>
</div>
<div class="row main-margin" id="about-me">
<h1 class="subtitle">
<span class="ml6">
<span class="text-wrapper-subtitle">
<span class="letters">About me</span>
</span>
</span>
</h1>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.0.2/anime.min.js"></script>
As a bonus, I would like a way to hide the text again every time it is scrolled out of screen.
This is my first StackOverflow question! I hope anyone can help me 😬
So there's most likely a better solution than this out there to be honest. But that's a quick way I found to get near to what you want. The problem with this is, that if it's in the viewport from the beginning and no scrolling occurs it will never show. You'll have to handle that.Using an IntersectionObserver would probably be a better fit for your case here.
// Wrap every letter in a span
var textWrapper = document.querySelector('.subtitle .ml6 .letters');
textWrapper.innerHTML = textWrapper.textContent.replace(/\S/g, "<span class='letter'>$&</span>");
const subtitle_animation = anime({
targets: '.subtitle .ml6 .letter',
translateY: ["1.1em", 0],
translateZ: 0,
duration: 750,
delay: (el, i) => 100 * i + 500
})
function isInViewport(el) {
const rect = el.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
const aboutme = document.getElementById('about-me');
let aboutme_vis = false
let ready_to_play = true
document.addEventListener('scroll', function () {
isInViewport(aboutme) ? aboutme_vis = true : aboutme_vis = false;
if (aboutme_vis && ready_to_play) {
subtitle_animation.restart();
setTimeout( () => {
aboutme.style.visibility = "visible";
} );
ready_to_play = false
}
if (!aboutme_vis){
aboutme.style.visibility = "hidden";
ready_to_play = true
}
});
/* Subtitle Animation */
.subtitle .ml6 {
position: relative;
font-size: 1em;
}
.ml6 .text-wrapper-subtitle {
position: relative;
display: inline-block;
padding-right: 10%;
overflow: hidden;
}
.ml6 .letter {
display: inline-block;
line-height: 1em;
transform-origin: 0 0;
}
#about-me {
visibility: hidden;
}
<div class="">
<h1>Title</h1>
<p>The subtitle About me can be found below! </p>
<h2>Random text so its possible to scroll: </h2>
<p>
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
<p>
<p>
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
<p>
<p>
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
<p>
</div>
<div class="row main-margin" id="about-me">
<h1 class="subtitle">
<span class="ml6">
<span class="text-wrapper-subtitle">
<span class="letters">About me</span>
</span>
</span>
</h1>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.0.2/anime.min.js"></script>