상세 컨텐츠

본문 제목

슬라이드 업 메뉴 구현하기 (with React)

프론트엔드

by pineSol 2024. 8. 9. 15:23

본문

안녕하세요. 디스턴스의 프론트엔드 개발자 박솔미입니다.

요즘 디스턴스는 9월에 있을 전남대 축제를 위해 기능 확장을 준비 하고 있습니다.🎉

 

그 중 채팅페이지에서도 '사진 전송 기능'을 추가하려고 합니다.

기존에는 채팅페이지에서 다음과 같은 기능들을 제공했었습니다.

  • 텍스트 채팅 기능
  • 일정 횟수에 도달하면 전화 버튼 활성화 기능
  • 신고하기 기능
  • 방 나가기 기능
  • 욕설 방지 필터링 기능

여기서 '사진 전송 기능'을 추가하면서 화면 UI가 다음과 같이 리디자인 되었습니다.

기능 추가 전후 화면

위에 사진을 보면 오른쪽 상단에 전화버튼, 나가기 버튼이 있고

왼쪽 하단에 신고하기 버튼이 있었습니다.

 

하지만 바뀐 디자인에서는 오른쪽 상단에 전화 버튼만 남겨두고

사진 전송을 포함한 모든 기능을 + 버튼 안에 메뉴로 넣게 되었습니다.

 

이에 해당 화면을 슬라이드 업 메뉴로 구현하게 되었습니다.

 


화면 레이어 구조 변경

변경된 디자인을 서비스에 적용하기 위하여 다음과 같이 구조화하였습니다.

화면 구조

//코드 구조 - 필요없는 내용은 제외시켰으니 구조만 참고해서 봐주세요

//ChatPage.jsx
<TopBar/>
<>
     <Messages/>
     <MessageInput/>
</>


//MessageInput.jsx
<MessageInputContainer>
     <Menu/>
     <InputContainer/>
</MessageInputContainer>


//Menu.jsx
<>
     <MenuUl/>
     <BlurBackground/>
</>

 

기존의 화면은 TopBar가 가장 위에 위치하고 Messages와 MessageInput의 z-index 높이가 모두 같았습니다.

하지만 슬라이드 업 메뉴를 구현하기 위해서는 MessageInput의 뒤에서 슬라이드가 올라와야 하므로

기존 레이어를 분리할 필요가 있었습니다.

수정 전후 레이어

다음과 같이 각 레이어를 분리하고

MessagesMessageInput 사이에 슬라이드 업 메뉴를 구현할 것입니다.

 

 

framer-motion으로 애니메이션 넣기

슬라이드 업 메뉴가 자연스럽게 올라오기 위해서는 애니메이션이 들어가야 합니다.

저는 framer-motion 라이브러리를 사용하여 구현했습니다.

*참고 url : https://www.framer.com/motion/animate-function/

 

animate | Framer for Developers

A function to manually start and control animations

www.framer.com

 

슬라이드 메뉴를 열고 닫을 수 있는 MenuToggle은 Motion.path를 사용하여 + 모양의 svg 파일을 만들고

+ 버튼을 클릭하면 오른쪽으로 45도 회전하면서 색상이 변경되도록 구현하였습니다.

 

메뉴 리스트 콘텐츠를 담고 있는 MenuUl요소는 framer-motion에서 보여주는 예시와 같이

useMenuAnimation 커스텀 훅을 만들어서 애니메이션을 구현하였습니다.

 

예시와 다른 점이 있다면 예시에서는 scale속성을 사용하여

메뉴가 왼쪽에서 오른쪽으로 순서대로 생성되는 듯한 애니메이션을 주었는데

저희 서비스에서는 아래에서 위로 올라오는 디자인이기 때문에

메뉴도 이와 같이 아래에서 위로 올라오도록 transform의 translateY 속성을 부여하여 구현하였습니다.

 

 

디자인 화면에서는 메뉴 슬라이드가 올라왔을 때 뒷 배경에 그라데이션으로 blur처리가 되어 있습니다.

이에 메뉴 아래에 BlurBackground 컴포넌트를 추가하고 position: absolute 속성을 부여하여

TopBar를 제외한 전체 화면에 스타일이 적용되도록 하였습니다. 

 

해당 내용들을 적용한 현재까지의 화면 레이어는 아래와 같습니다.

BlurBackground를 적용한 화면 레이어

 

버튼이 눌리지 않는 이슈

여기까지 구현하고 기능을 연결하려고 했더니 MenuUl 안에 버튼이 눌리지 않는 이슈가 발생했습니다.

개발자 도구로 살펴보니 MenuUl이 뭔가에 덮에 있는 것을 발견했습니다.

 

z-index 요소를 살펴보니 MessageInput의 z-index가 10이고

MenuUl과 InputContainer를 감싸고 있는 MessageInputContainer의 z-index요소는 auto였습니다.

이런 경우 부모의 요소를 따라가므로 MessageInputContainer의 z-index는 10입니다.

 

MenuUl의 z-index는 -1을 부여하였으므로 최종적으로 9가 되서 MessageInputContainer의 아래에 위치하게되는 것이었습니다.

이 부분을 발견하지 못해서 버튼이 눌리지 않는 이슈가 발생했던 것이었습니다.

 

이슈 해결

 

슬라이드 업 메뉴가 올라올 때 InputContainer뒤에서 시트가 올라와야 자연스럽기 때문에

메뉴가 닫혀 있을 때 MenuUl은 InputContainer 뒤에 위치했다가

메뉴가 열렸을 때 MenuUl가 InputContainer 앞에 위치하도록 수정해야 했습니다.

 

저희 코드는 styled-components로 구현되어 있기 때문에

해당 내용은 $isOpen이라는 prop을 사용하여 z-index 속성을 조건에 맞게 제어하였습니다.

position: relative;
z-index:  ${({$isOpen}) => $isOpen? "1" : '-1'}

 

이제 MenuUl이 열려있는 상태일 때는 z-index가 1이 부여되어 MessageInputContainer보다 위에 위치하게 되었습니다.

 

해당 이슈를 해결한 화면 레이어를 구조화하면 아래와 같습니다.

메뉴가 여닫힐 때 MenuUl의 위치 변화

이제 버튼도 잘 작동하게 되었습니다😀

 

 

후기

css에서 부모 요소가 자식에게 상속되는 부분을 간과하는 경우가 많았습니다.

스타일이 기대한대로 적용되지 않았을 때, 개발자 도구를 통해 해당 요소에 적용된 스타일을 확인해보면

부모 요소가 미치는 영향 때문이라는 것을 자주 깨닫곤 했습니다.

 

(이번에도 어김없이 부모 요소의 영향으로 생긴 이슈였습니다,,ㅎㅎ)

그래도 이런 시행착오를 여러 번 겪다보니 오류를 잡아내는 속도가 점점 빨라지는 것을 느꼈습니다.

 

또한 이번 기회에 z-index를 제대로 활용해볼 수 있었습니다.

상대적으로 계산되는 요소를 잘 고려해서 레이어를 잘 구현하면

다양하고 심미적인 화면 구현이 가능하겠다는 생각이 들었습니다.

 

css는 오류메세지가 제공되는 것도 아니라서 안 풀릴 때 제일 답답하지만

제대로 구현되었을 때 디자인적으로 만족스러우면 그만큼 큰 재미도 느낄 수 있는 분야인 것 같습니다:)

관련글 더보기