ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React] Styled-components와 React(+ Typescript)로 타이핑 애니메이션 만들기
    development/React 2022. 10. 9. 00:17

    안녕하세요.

     

    오늘은 제가 프로필 페이지를 제작하면서 만들었던 간단한 타이핑 애니메이션에 대해 포스팅하려고 합니다.

    정말 간단한 애니메이션인데, 혹시나 비슷한 걸 만들고자 하시는 분께 도움이 되고자 간략하게 포스팅 해봅니다.

     

    완성된 타이핑 애니메이션.

    1. UI 제작하기

    이번 프로젝트에선 기본적으로 React 프로젝트가 준비되어 있다는 가정 하에 진행하도록 하겠습니다.

    우선, 타이핑 애니메이션 이전에 보여지고픈 UI를 제작해줍니다.

     

    // ...
    
    const MainTitle = styled.div`
      text-align: left;
      font-weight: 500;
      margin: 2rem 0;
      line-height: 1;
      font-size: 7rem;
      position: relative;
      display: flex;
      align-items: center;
      justify-content: center;
      
      font-family: ${(props) => props.theme.fontFamily.special}; // Theme
      color: ${(props) => props.theme.color.text.light}; // Theme
     `;
     
     // ...
     
     return (
     	<MainTitle>HELLO, World!</MainTitle>
     )

    font-family나 color와 같은 세팅은 따로 설정해준 테마를 사용해 설정했습니다.

    이러한 코드를 렌더링하게 되면, 다음처럼 UI가 완성됩니다.

    아직은 그저 텍스트일 뿐 입니다.

    이제 문장 앞의 터미널 기호와 커서를 추가해보겠습니다.

     

    2. Terminal 기호, Cursor UI 렌더링하기

    // ...
    
    
    const MainTitle = styled.div`
      // ... 생략 ...
    
      &:before {
        content: '>';
        position: absolute;
        left: -5rem;
        top: 0;
      }
    
      &::after {
        content: '';
        display: block;
        position: absolute;
        right: -3rem;
        width: 1.5rem;
        height: 100%;
        top: 0rem;
        background-color: #ffffff60;
    
      }
    `;
    
    // ...

    터미널 기호와 커서 UI 모두 의미가 없는 뷰용 요소이기 때문에 ::before, ::after를 사용해 요소를 추가했습니다.

    직접적인 render return 부의 코드 변화는 없습니다.

    터미널 기호와 커서 UI가 추가된 내용

    다음으로는 커서의 깜빡이는 애니메이션을 제작하겠습니다.

     

    3. Cursor animation 제작하기

    const CursorAnimation = keyframes`
      0%, 45%, 90%, 100% {
        opacity: 1;
      }
    
      50%, 85% {
        opacity: 0;
      }
    `;
    
    
    
    const MainTitle = styled.div`
      // ... 생략
        
      &:before {
      	// ... 생략
      }
    
      &::after {
      	// ... 생략
    
        animation: ${CursorAnimation} 1s infinite;
      }
    `;

    styled-components의 keyframe을 사용해 커서가 깜빡이는 듯한 애니메이션을 1초의 지속시간을 두어 설정해주었습니다.

    이제 뭔가 애니메이션처럼 보입니다.

    다음은 각 글자가 타이핑되는 듯한 애니메이션을 제작해 보겠습니다.

     

    4. 타이핑 애니메이션 제작하기

    우선 저는 개별 문자열 하나씩의 컨트롤을 위해 텍스트를 배열로 변환하여 각 파츠를 렌더링 하는 방식으로 진행했습니다.

    그리고 파츠별로 분리한 문자열을 기본적으로 width를 0으로 주어 렌더링 되지 않게 하고, 렌더링 될 순서가 됐을 때 width를 본래 크기로 늘려주어 화면에 타이핑 되는 것 같은 효과를 주었습니다.

     

    1. 문자열을 배열로 변환하여 map으로 각 요소를 span으로 감싸 렌더링
    2. span 요소는 0%에선 width=0 인 상태를 유지하도록 하고, 100%에선 width=max-content 인 애니메이션이 적용되어 있음
    3. 각 렌더링 요소는 기본적으로 width=0 인 상태로 유지 (화면상엔 출력되지 않는 상태)
    4. 각 요소의 styled props로 애니메이션 딜레이 시간을 index * 타이핑 간격 시간으로 계산하여 전달
    5. styled에서 애니메이션 딜레이를 적용
    6. 화면상에 글자 순서대로 출력
    const CursorAnimation = keyframes`
      // ... 생략
    `;
    
    const MainTitle = styled.div`
      // ... 생략
    `;
    
    
    // 각 요소 타이핑 애니메이션
    const FlickerAnimation = keyframes`
      0% {
        width: 0px;
      }
    
      100% {
        width: max-content;
      }
    `;
    
    const TextPart = styled.span<{ delaySecond: number }>`
      display: inline-block;
      overflow: hidden;
      width: 0px;
      animation: ${FlickerAnimation} 0.1s forwards;
      animation-delay: ${(props) => props.delaySecond}s;
    `;
    
    const typingAnimationText = 'HELLO, World!'; // 타이핑 애니메이션 문구
    const partAnimation = 0.3; // 타이핑 딜레이 (second)
    const typingAnimationTextArray = Array.from(typingAnimationText); // 문구 배열 변환
    
    // ...
    
    return (
    	<MainTitle>
          {typingAnimationTextArray.map((part, i) => (
            <TextPart key={i} delaySecond={partAnimation * i}>
              {part}
            </TextPart>
          ))}
        </MainTitle>
    )

    드디어 완성된 애니메이션!

    이후 필요하다면 저처럼 컬러를 일부 변경하거나 하는.. 커스텀으로 마음에 들게 수정하시면 완성입니다!

    참고로 완성된 전체 소스코드는 제 Github에 업로드 되어 있으니 풀 소스코드가 보고 싶으시면 오시면 됩니다~.

    저 소스코드가 완성된 당시의 PR 링크 올려드립니다.

     

    혹시 잘못된 부분이 있다면 피드백 부탁드립니다.

    감사합니다.

Designed by Tistory.