무한으로 반복되는 텍스트 애니메이션은 가끔씩은 필요할 때가 있습니다. 라이브러리를 사용해도 되겠다고 생각은 하지만, 라이브러리를 잘 알지 못하기 때문에 이번 기회에 직접 제작해 보았습니다.
라이브러리를 사용하지 않고 Vanilla Javascript를 이용해 만듭니다.
.move-box
의 유형은 2가지 입니다.
- 하나는 일반적인 텍스트 box
- 애니메이션을 가지고 있는 텍스트 box
const titlemoveBox = document.querySelectorAll(".move-box");
2개의 .moveBox
에게 동시에 같은 동작을 주기 위해서 querySelectorAll
을 이용해 nodelist의 배열형식으로 변수에 담습니다.
담긴 유사배열은 forEach
메소드를 이용해 각 요소에 접근에 동일한 동작을 하도록 할 예정입니다.
const boxCount = titlemoveBox[0].childElementCount;
//nodelist에서 다른 요소들도 HTML에 구조는 같기때문에 대표적인 요소 하나만 가져와 자식 요소들의 숫자를 변수에 담는다.
const moveRate = 100 / (boxCount + 1);
//전체 높이를 100으로 봤을때 요소의 갯수마다 동일한 높이로 옮기기 위해 자동으로 계산하도록 한다.
// 1을 더한건, 클론이 될 요소 때문에 1을 더한다.
let num = 0;
//num은 titleMove()함수가 호출될때마다 1씩 증가하도록 해서 요소의 갯수보다 크거나 같으면 0이 되어 무한 루프를 돌 수 있도록 해주는 변수
function cloneBox(){
//클론 Movebox 마지막 div
titlemoveBox.forEach((elem) => {
////////--마지막 요소를 클론--///////////////
//elem은 .move-box를 가진 요소들 ( 2개 )
let lastChild = elem.lastElementChild;
//마지막 요소들을 변수에 담는다.
let cloneLast = lastChild.cloneNode(true);
//마지막요소를 클론해 변수에 담는다.
elem.prepend(cloneLast);
//클론한 요소를 첫번째 자식 요소로 추가한다.
cloneLast.style.opacity = 0;
//처음 나타났을때는 클론된 요소가 보이지 않기를 원하기 때문에 opacity를 0으로 한다.
//////--opacity를 0에서 1로 만드는 구간--///////////////
setTimeout(() => {
cloneLast.style.opacity = 1;
cloneLast.classList.add('ani');
lastChild.classList.add('ani');
//setTimeout을 이용해 로딩 후 첫번째 요소(클론하지 않은 원래의 .move-box의 요소(DIGITAL /DESiGN 텍스트가 있는 요소)가 화면에 나타난 이 후에 opacity를 1로 만들어서 클론된 요소가 나타나게 한다.
// 그리고 ani클래스를 마지막요소와 클론된 요소에 같은 부여해 애니메이션 재생시작 타이밍을 같이해 딜레이되는 오류를 막는다.
}, 1000); //로딩 될때 box가 나타난 이후의 시간
});
}
requestAnimationFrame()
을 이용해 자기자신을 콜백시켜, 자연스러우면서도 반복적인 애니메이션을 만들려고 했습니다.
function titleMove() {
num++;
titlemoveBox.forEach((elem, idx) => {
if (num >= boxCount) {
elem.style.transform = `translateY(-${moveRate * num}%)`;
//////--마지막 요소에서 클론된 요소로 바꿔치기하는 코드--///////////////
setTimeout(() => {
num = 0;
elem.style.transition = "none";
elem.style.transform = `translateY(-${moveRate * num}%)`;
}, 1210);
//requestAnimation반복 시간(0.4) + 트랜지션시간(0.8) + 약간의 여유(0.1);
// 아래에서 위로 올라오는 동작의 소요시간이 다 완료 된 다음 바꿔치기를 해야 자연스러운데 바로 하게 되면 조금 '틱틱'거리는 감이 있어서 0.1초를 더 더했다.
} else {
elem.style.transition = "0.8s";
elem.style.transform = `translateY(-${moveRate * num}%)`;
}
});
//////--4초마다 반복 실행되도록 하는 코드--///////////////
setTimeout(() => {
window.requestAnimationFrame(titleMove);
}, 4000); //시간s마다 텍스트가 올라가는 애니메이션 무한 실행
}
num
titleMove()
함수가 실행될때마다 증가합니다.num
의 값에 따라 .box-move
의 transformY
의 값이 증가하도록 만들어 text가 아래에서 위로 올라가는 모습이 보이도록 만듭니다.if조건식
을 이용해 마지막 요소가 해당하는 transformY
가 발생한 후에 num의 값을 0으
로 재할당해서 클론된 요소가 보이도록 합니다.transition
의 값이 없어야 변화가 눈에 보이지 않아 무한루프처럼 보이게 됩니다.transition의 값을 지우지 않는다면 빠르게 클론 요소로 옮겨지는 것을 볼 수 있을 겁니다.
아래의 코드펜에서 볼 수 있습니다.
window.addEventListener('load',()=>{
cloneBox();
titleMove();
})
윈도우가 로드되자마자 두개의 함수를 호출하면 무한 루프 텍스트 애니메이션이 작동이 됩니다.
이번에도 겹치는 코드들이 있어서 조그만 코드를 정리하면 좋지 않을까하는 생각이 들었습니다. 그리고 애니메이션의 타이밍을 잡을때 transition의 값을 가져와 변수에 담는다면 좋을텐데 라는 생각이 들었지만, 어떤 방법을 사용하면 좋을지 잘 모르겠어서 아쉬움이 있습니다.
더 좋은 방법이 있다면 알려주시면 감사하겠습니다.^^ㅎ
reference