개발자일기/Tutorial

한 글자씩 나타나는 애니메이션(CSS, VanilaJS)

뫙뭉 2022. 1. 13. 22:05
반응형

웹사이트에 심심함을 덜어줄 무언가가 필요하다!!

 

얼마전에 포트폴리오를 재정비할 계획이 있었다.

사실 신입 포트폴리오, 심지어 비전공자라 하면 쓸 말이 많지가 않더라. 나만 그런것인가...

그렇다면 뭔가 심심하지 않은 애니메이션으로 시각적 즐거움을 채우면 좋지 않을까 라는 생각이 자연스럽게 들게된다.

뭔가 샤랄라~ 하는 느낌으로 한글자씩 나타나는 애니메이션을 넣으면 좋겠다라는 생각에 일단 코드를 생각나는대로 끄적여 보았다.

 

생각의 흐름

CSS만으로 해결 할 수 있겠는데..?

일단 html에 적어야겠지. 가장 처음 적었던 코드는 다음과 같다.

<span class='word'>TEST</span>

 

우선 기본적으로 드는 생각은 글자를 쪼개야 한다는 것.

한글자씩 나타나야 하기 때문에 도저히 하나의 태그 안에 글자가 있으면 해결방법이 떠오르지 않는다. 코딩의 고수분들은 혹시 또 모르겠지만 나의 머리로는 불가능했다.

 

우선 첫번째로 생각했던 것은 CSS로만 해결이 가능 할 수도...? 였다.

그렇게 생각했던 근거는 nth-child 라는 가상선택자의 존재이다.

다음과 같이 html 코드를 짰다고 가정해보자.

<span style='--i: 1'>T</span>
<span style='--i: 2'>E</span>
<span style='--i: 3'>S</span>
<span style='--i: 4'>T</span>

 

 

위와 같이 태그를 짤 당시에 변수를 설정하면 calc()함수를 이용하여 animation-delay를 각 태그마다 설정할 수 있을 것이다.

하지만 이 방법의 문제점. 원하는 문자를 모두 직접 각각 태그를 나누어서 코드를 짜야 한다는 것... 그렇게 한다면 굉장히 시간이 많이 걸릴 것이고 나중에 수정할 때 엄청난 노동을 겪게 될 것이 뻔했다.

나는 일시적인 해결이 아닌 나중에도 써먹을 수 있는 방법을 원했다. 그렇기에 다른 방법을 생각해야 한다.

 

JS로 글자부터 나눠보자

그렇다면 일단 JS는 필수적으로 써야겠고... 그 다음 생각했던 것.

글자를 JS를 통해 자동으로 쪼개주는 것부터 생각하자. 그래야 나중에 문자열만 띡! 하고 입력해도 바로 샤랄라~ 하는 효과를 넣을 수 있을 것이다.

 

작전은 이러했다.

1. html에는 그냥 원하는 문자열을 입력한다. ex) <span>TEST</span>

2. 함수를 이용해서 쪼갠후

3. 원래 있던 것은 삭제를 하고

4. 쪼개어진 태그들을 원래 문자열이 있던 자리에 차라락 넣는다.

 

그리하여 만들어진 함수는 다음과 같다.

 

const word = document.querySelector('.word'); // 문자열이 적혀있는 태그

function splitLetters (word) {
    const content = word.innerHTML;
    word.innerHTML = ''; // 원래 문자열은 저장하고 태그는 삭제
    
    for(let i = 0; i < content.length; i++){
        let letter = document.createElement('span');
        letter.className = 'letter';
        letter.innerHTML = content.charAt(i);
        word.appendChild(letter);
    }
}


splitLetters(word);

이렇게 하면 word 클래스의 자식으로 글자가 각각 span태그로 쪼개져서 들어가게 된다.

여기서 핵심은 charAt. 이 API가 있다는 것을 잊고 있어서 한참을 헤맸다. 역시 어떤 API가 있는지 알고 있는 것이 굉장히 중요하다 이말이다.

 

이렇게 함수를 완성하여 모든 것이 끝난줄 알며 잠시 환호를 질렀으나 지금까지 한 것은 그냥 글자만 쪼갠것.

샤랄라~ 는 아직 없다 이말이다.

 

다음 할 작업은 우아한 샤랄라 이다.

 

쪼갠 글자로 샤랄라~를 구현하자

여기까지 했으면 그 다음 작업은 그렇게 복잡할 것이 없다.

작전은 다음과 같다.

 

1. css를 구현해 놓고 opacity: 0과 transform: translateY(20px)를 설정해놓는다. (원하는 방향에 따라 알아서 설정)

2. on 클래스에 opacity: 1 과 transform: none 설정.

3. setTimeout 함수를 이용하여 앞글자부터 시간차로 on 클래스를 부여한다.

 

그렇게 해서 탄생한 함수는 다음과 같다.

//index.js

const word = document.querySelector('.word')

const displayLetters = (arr) => {
  for(let i = 0; i < arr.length; i++){
    addClassname(arr, i)
  }
}

const addClassname = (arr, i) => {
  setTimeout(() => {    
    arr[i].classList.add('on')
  }, 350+(i*80)) // i 뒤에 곱해지는 수로 애니메이션 조정
}

const splitLetters = (word) => {
  const letters = [];
  const content = word.innerHTML;
  word.innerHTML = '';

  for(let i = 0; i < content.length; i++){
    let letter = document.createElement('span');
    letter.className = 'letter';
    letter.innerHTML = content.charAt(i);
    word.appendChild(letter);
    letters.push(letter);
  }
  
  displayLetters(letters);
}

splitLetters(word);

 

/* style.css */

body{
  margin:0;
}

.word{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -100%);
  font-size: 70px;
}

.letter{
  display: inline-block;
  transform: translateY(20px);
  opacity: 0;
  transition: all 500ms ease-in;
}

.letter.on{
  transform: none;
  opacity: 1;
}

 

참고로 inline 속성을 갖고 있는 span태그는 transform이 적용되지 않는다. 따라서 display 속성을 inline-block으로 적용시켜줘야 transform이 정상적으로 작동한다.

특정 방향에서 나타나는 것이 아닌 opacity만을 이용한 효과를 원한다면 굳이 속성을 변환시킬 필요는 없다.

 

이렇게 만들었으니 결과물을 자랑하지 않을 수가 없다 이말이다.

최종적으로 만들어진 샤랄라이다.

 

마무으리

또 한가지를 배웠던 뜻깊은 시간이었다. 이번 작업 또한 혼자만의 힘으로는 해내지 못했다. 검색의 유혹을 뿌리치지 못하고 열심히 구글링을 했다는...

그런데 구글링만으로는 자료를 찾기 쉽지가 않아 codepen에서 one letter, word animation 이라는 키워드로 검색을 해서 참고자료를 발견 했던 것 같다.

간단한 작업이지만 하나씩 직접 만들어 볼 때마다 내것이 되어가는 것 같아 굉장히 뿌듯하다.

다음에도 간단하지만 유용한 자료들로 찾아뵙도록 하겠다.

 

 

 

 
반응형