간단한 Modal Bottom Sheet 를 만들어보자

기운찬곰·2023년 4월 12일
2
post-thumbnail

Overview

요즘에 저는 사이드 프로젝트를 하고 있습니다. 사이드 프로젝트를 하면 뭔가 새로운 걸 해볼 수 있다는 것이 가장 좋은거 같습니다. 그 중에서 이번 시간에 다뤄볼 Modal Bottom Sheet도 새로운 경험이었습니다. 그 동안 안 해봤던 것이기 때문입니다.


요즘에는 모바일을 사람들이 많이 사용하기 때문에 모바일 웹 형태에 사이트를 만들고 있습니다. 그렇다보니 모바일 친화적인 UI를 구성하려는 시도를 하고 있는데요. 그 중에서 밑에서 위로 올라오는 팝업 형태 많이들 보셨을 겁니다.

저도 어떤 예시가 있을까 찾아보니 교보문고 카테고리 선택할 때도 있고 리디에서 작품 소개 볼 때도 있네요. 그만큼 많이 사용되는 UI인거 같습니다.

교보문고 처럼 단순한 팝업 형태도 있을 수 있고, 좀 더 나아가서 콴다처럼 터치 이벤트를 통해 자연스럽게 위로 올리고 내릴 수 있게도 구현할 수 있을 듯합니다. 하지만 이 때는 난이도가 상승하겠죠? ㅎㅎ

저는 일단 교보문고 스타일처럼 단순하게 가도록 하겠습니다. 기회가 된다면 콴다처럼 한 번 만들어보는 시도를 해보는 것도 좋을 거 같습니다. 아래는 저희가 만들려는 화면입니다. 필터를 선택했을 때 밑에서 위로 Modal Bottom Sheet가 짠~ 하고 나오도록 하는 것이 목표입니다.


기본 레이아웃 구성하기

일단 레이아웃을 잡을 때 검은 배경화면에 아래에는 흰색 배경의 콘텐츠 박스가 보여야 합니다. 흠... 일단 검은 배경화면부터 잡아볼까요? 여기서 주의해야 할 점은 스크롤을 좀 내린상태에서도 저 검은 배경화면은 꽉 차서 보여야 한다는 것입니다.

이 때 사용하면 좋은게 바로 fixed랑 inset-0인데요. inset의 의미는 사실 top, right, bottom, left의 축약형입니다. 즉, inset-0은 inset: 0과 같고, top-0, right-0, bottom-0, left-0과 같습니다.

<div className="fixed inset-0 bg-black/50 z-10">

결국 저 의미는 화면 전체를 다 덮으라는 말과 동일합니다. 그것도 fixed된 형태로요. 이제 무조건 검은 배경화면이 전체를 다 덮을 것입니다.

이제 흰색 Bottom Sheet을 보여줘야 하는데 이때는 간단하게 "absolute bottom-0 left-0" 을 사용했습니다.

<div className="absolute bottom-0 left-0 w-full max-w-screen-md h-[420px] bg-white rounded-t-lg px-4 pb-10" />


분명 저는 검은 배경에 화면을 꽉 찬 상태로 만들었고 당연히 뒤에 페이지는 스크롤이 안될거라 생각했습니다. 하지만... 뒤에가 너무 스크롤이 잘 되더군요. ㅎㅎ

몇가지 글을 찾아봤는데 이런 현상이 아마 일반적인거 같습니다. 해결책은 팝업을 띄울 때 직접 document.body.style에 overflow를 hidden으로 하고, 팝업이 없어지면 다시 스크롤이 되도록 할 수 있더군요. 이게 최선일까? 싶긴 하지만 잘 되긴 합니다.

혹시 더 좋은 방법이 있으면 댓글로 알려주시면 좋겠습니다..ㅎㅎ

  useEffect(() => {
    document.body.style.overflow = "hidden";

    return () => {
      document.body.style.overflow = "unset";
    };
  }, []);

애니메이션 적용하기 (feat. tailwindcss)

저는 처음에 transform: translateY + transition 조합으로 간단하게 아래에서 위로 애니메이션이 가능할거라고 생각했습니다.

하지만 이렇게 해줬을 때 초기에 애니메이션이 작동하지 않습니다. 찾아보니 보통 저 조합으로 사용되는 예시가 :hover나 :active 같은 가상 셀렉터랑 사용하는게 일반적이더군요. 즉, 초기에 작동하는 애니메이션은 직접 animation을 사용해야 할 거 같습니다.

"일반적으로 트랜지션 효과는 요소 프로퍼티값이 다른 값으로 변화할 때 주로 사용하며 요소의 로드와 함께 자동으로 발동되지 않는다.”"

결국 tailwindcss에서 keyframs를 통해 직접 애니메이션을 추가 해줬습니다.

extend: {
      keyframes: {
        "bottom-sheet-up": {
          "0%": { transform: "translateY(420px)" },
          "100%": { transform: "translateY(0)" },
        },
        "bottom-sheet-down": {
          "0%": { transform: "translateY(0)" },
          "100%": { transform: "translateY(420px)" },
        },
      },
    },

그리고 실제 적용할 때 중요한 점은 duration이 있어야 한다는 것입니다.

<div className="w-full max-w-screen-md h-[420px] bg-white rounded-t-lg px-4 pb-10 animate-[bottom-sheet-up_200ms_ease-in-out]">

일단 이렇게 해서 완성된 결과 입니다.


보완할 점 (생각해볼만한 문제)

  • 닫기 버튼을 눌렀을 때도 애니메이션이 적용되면서 아래로 쓱 사라지도록 하려면 어떻게 해야할까?
  • 닫기 버튼 없이 터치 이벤트를 통해 쓱 잡고 내리도록 구현하려면 어떻게 해야할까? 만약 그렇게 한다면 어느수준까지 내려야 닫히도록 할 것인가 이런것도 고려해야겠지?
  • 이것을 라이브러리로 잘 만들어보면 어떨까?

참고 자료

profile
배움을 좋아합니다. 새로운 것을 좋아합니다.

0개의 댓글

관련 채용 정보