본문 바로가기

카테고리 없음

[React] styled-components 에서 opacity 없이 모달 애니메이션 넣기

모달을 조건부 렌더링으로 구현하였지만, 애니메이션 효과가 없어서 UI가 너무 딱딱하게 느껴졌다.

검색해보니 대부분은 opacity: 0 으로 투명하게 만들고 클릭시 1로 바꿔 보이게끔 하는 방법을 사용하는 내용이었는데, 여러 시행착오 끝에 결론은 @keyframes와 animation을 이용하여 애니메이션을 추가하여 문제를 해결했다.

모달창을 구현하기 위해 3가지 조건이 필요했다.

  • 모달창이 나타날 때 다른 요소보다 위에 위치하여 렌더링 되어야 했고
  • 내부 버튼들도 잘 동작해야 했으며
  • 마지막으로 백그라운드를 눌러도 모달창을 닫을 수 있어야 했다.

opacity를 사용하면 문제점

  1. 모달 백그라운드 뒤의 버튼이나 요소들이 클릭되지 않거나 동작하지 않는 문제가 발생한다. pointer-events : none 속성을 사용하여 제어할 수 있으나, 백그라운드 클릭으로 닫을수가 없고, 모달창 내부의 버튼 등을 사용할 수 없게 된다.
  2. 브라우저에는 보이지 않지만, 실제로는 렌더링이 되어 있기 때문에 버그와 같은 문제가 발생할 수 있으며, 대규모 웹의 경우 메모리 낭비 문제가 발생할 수 있다.

컴포넌트

모달을 더욱 효율적으로 제어하기 위해 커스텀 훅을 만들어 props 없이도 모달을 제어할 수 있도록 구현하였다.
또한, 모달이 생성 되면 백그라운드와 x 버튼을 누를시 모달이 사라지는 기능을 추가했다.

 

// Modal.tsx
import React,{ useState } from 'react';
        ...

const Header = () => {
     const { clickHandler } = useModal();
    return(
            ...
      // 클릭시 모달 생성
     <LoginSection>
        <p className="login" onClick={() => clickHandler(true)}>
              로그인
        </p>
     </LoginSection>
  );
};

const Modal = () => {
  const {isOpen , clickHandler } = useModal();

  return (
    //  isOpen 기준 조건부 렌더링
    <Container display={isOpen ? 'flex' : 'none'}>

        // 모달 백그라운드 클릭시 isOpen 값이 false로 바뀌는 함수
      <ModalBackground onClick={() => clickHandler(false)} />
      <ModalWindow>

        // x 버튼 클릭시 isOpen 값이 false로 바뀌는 함수
        <p className="close" onClick={() => clickHandler(false)}>
          &times;
        </p>
      </ModalWindow>
    </Container>
  );
};
// useClick.ts

import { useState } from 'react';

//useModal의 interface
interface ModalHook {
  isClick: boolean;
  clickHandler: () => void;
}

// 모달을 제어하는 커스텀 훅
const useModal = () : ModalHook => {
  const [isOpen, setIsOpen] = useState(false); 

  // 클릭 시 isOpen의 boolean 값 변경으로 모달을 제어하는 기능
  const clickHandler = (isClicked : boolean) => {
      setClick(isClicked);
    };

  return { isOpen, clickHandler }
}

styled-components

백그라운드를 클릭할 때 모달이 사라지는 설정과 애니메이션을 적용하여 부드럽게 모달이 나타나고 사라지도록 설정했다.

 

// modalstyled.ts;

const Container = styled.div`
  display: ${(props) => props.display || 'none'};
  justify-content: center;
  align-items: center;
  background-color: rgb(0, 0, 0, 0.6);
`;

const ModalBackground = styled.div`
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
`;

// 모달 애니메이션 적용 설정
const ModalWindow = styled.div`
  position: relative;
  width: 380px;
  height: 550px;
  background: white;
  padding: 0 30px;
  animation: modaldown 0.5s linear;

  @keyframes modaldown {
    from {
      transform: translateY(-10%);
    }
    to {
      transform: translateY(0);
    }
  }

  .close {
    position: absolute;
    right: 15px;
    top: 5px;
    cursor: pointer;
    font-size: 25px;
  }
`;

 

  • animation : modaldown 0.5s linear; 속성은 animation-name(임의의 이름), animation-delay 순 으로 설정한것이다.
  • @keyframes 규칙에서 from(애니메이션 시작)translateY(-10%) 약간 위로 이동하도록 설정했고, to(종료)translateY(0) 원래대로 돌아오도록 설정했다.

 

 

 

원하는 결과물이 나왔다.