무한루프 텍스트 애니메이션 만들기

n-u·2022년 11월 3일
1

INTERACTION

목록 보기
1/1
post-thumbnail

무한으로 반복되는 텍스트 애니메이션은 가끔씩은 필요할 때가 있습니다. 라이브러리를 사용해도 되겠다고 생각은 하지만, 라이브러리를 잘 알지 못하기 때문에 이번 기회에 직접 제작해 보았습니다.

라이브러리를 사용하지 않고 Vanilla Javascript를 이용해 만듭니다.

✔️ 구상

  • 슬라이드를 만드는 방법으로 제작합니다.
    • 마지막 요소를 클론하여, 첫번째 요소 앞에 붙여주고, 마지막 요소가 나타난 후 바로 클론된 요소의 위치로 이동하여 제작합니다.

  • 전체 감싸고 있는 요소의 높이를 100%으로 합니다
  • 안의 요소의 갯수가 변경되어도 코드를 수정하지 않아도 동작이 되도록 구현하는 것을 목표로 합니다.
  • 두 개 이상의 요소에 같은 애니메이션을 부여하도록 합니다.

✔️ HTML

.move-box의 유형은 2가지 입니다.

  1. 하나는 일반적인 텍스트 box
  2. 애니메이션을 가지고 있는 텍스트 box

✔️ JAVASCRIPT

🔸 변수

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-movetransformY의 값이 증가하도록 만들어 text가 아래에서 위로 올라가는 모습이 보이도록 만듭니다.
    • if조건식을 이용해 마지막 요소가 해당하는 transformY가 발생한 후에 num의 값을 0으로 재할당해서 클론된 요소가 보이도록 합니다.
    • 이때, transition의 값이 없어야 변화가 눈에 보이지 않아 무한루프처럼 보이게 됩니다.
      • transition의 값을 지우지 않는다면 빠르게 클론 요소로 옮겨지는 것을 볼 수 있을 겁니다.

      • 아래의 코드펜에서 볼 수 있습니다.

🔸 호출

window.addEventListener('load',()=>{
  cloneBox();
  titleMove();  
})

윈도우가 로드되자마자 두개의 함수를 호출하면 무한 루프 텍스트 애니메이션이 작동이 됩니다.

✔️ 마치며..

이번에도 겹치는 코드들이 있어서 조그만 코드를 정리하면 좋지 않을까하는 생각이 들었습니다. 그리고 애니메이션의 타이밍을 잡을때 transition의 값을 가져와 변수에 담는다면 좋을텐데 라는 생각이 들었지만, 어떤 방법을 사용하면 좋을지 잘 모르겠어서 아쉬움이 있습니다.

더 좋은 방법이 있다면 알려주시면 감사하겠습니다.^^ㅎ

reference

profile
기록하며 발전하는 삶

0개의 댓글