안녕하세요. 디스턴스의 프론트엔드 개발자 박솔미입니다.
요즘 디스턴스는 9월에 있을 전남대 축제를 위해 기능 확장을 준비 하고 있습니다.🎉
그 중 채팅페이지에서도 '사진 전송 기능'을 추가하려고 합니다.
기존에는 채팅페이지에서 다음과 같은 기능들을 제공했었습니다.
여기서 '사진 전송 기능'을 추가하면서 화면 UI가 다음과 같이 리디자인 되었습니다.
위에 사진을 보면 오른쪽 상단에 전화버튼, 나가기 버튼이 있고
왼쪽 하단에 신고하기 버튼이 있었습니다.
하지만 바뀐 디자인에서는 오른쪽 상단에 전화 버튼만 남겨두고
사진 전송을 포함한 모든 기능을 + 버튼 안에 메뉴로 넣게 되었습니다.
이에 해당 화면을 슬라이드 업 메뉴로 구현하게 되었습니다.
변경된 디자인을 서비스에 적용하기 위하여 다음과 같이 구조화하였습니다.
//코드 구조 - 필요없는 내용은 제외시켰으니 구조만 참고해서 봐주세요
//ChatPage.jsx
<TopBar/>
<>
<Messages/>
<MessageInput/>
</>
//MessageInput.jsx
<MessageInputContainer>
<Menu/>
<InputContainer/>
</MessageInputContainer>
//Menu.jsx
<>
<MenuUl/>
<BlurBackground/>
</>
기존의 화면은 TopBar가 가장 위에 위치하고 Messages와 MessageInput의 z-index 높이가 모두 같았습니다.
하지만 슬라이드 업 메뉴를 구현하기 위해서는 MessageInput의 뒤에서 슬라이드가 올라와야 하므로
기존 레이어를 분리할 필요가 있었습니다.
다음과 같이 각 레이어를 분리하고
Messages와 MessageInput 사이에 슬라이드 업 메뉴를 구현할 것입니다.
슬라이드 업 메뉴가 자연스럽게 올라오기 위해서는 애니메이션이 들어가야 합니다.
저는 framer-motion 라이브러리를 사용하여 구현했습니다.
*참고 url : https://www.framer.com/motion/animate-function/
슬라이드 메뉴를 열고 닫을 수 있는 MenuToggle은 Motion.path를 사용하여 + 모양의 svg 파일을 만들고
+ 버튼을 클릭하면 오른쪽으로 45도 회전하면서 색상이 변경되도록 구현하였습니다.
메뉴 리스트 콘텐츠를 담고 있는 MenuUl요소는 framer-motion에서 보여주는 예시와 같이
useMenuAnimation 커스텀 훅을 만들어서 애니메이션을 구현하였습니다.
예시와 다른 점이 있다면 예시에서는 scale속성을 사용하여
메뉴가 왼쪽에서 오른쪽으로 순서대로 생성되는 듯한 애니메이션을 주었는데
저희 서비스에서는 아래에서 위로 올라오는 디자인이기 때문에
메뉴도 이와 같이 아래에서 위로 올라오도록 transform의 translateY 속성을 부여하여 구현하였습니다.
디자인 화면에서는 메뉴 슬라이드가 올라왔을 때 뒷 배경에 그라데이션으로 blur처리가 되어 있습니다.
이에 메뉴 아래에 BlurBackground 컴포넌트를 추가하고 position: absolute 속성을 부여하여
TopBar를 제외한 전체 화면에 스타일이 적용되도록 하였습니다.
해당 내용들을 적용한 현재까지의 화면 레이어는 아래와 같습니다.
여기까지 구현하고 기능을 연결하려고 했더니 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보다 위에 위치하게 되었습니다.
해당 이슈를 해결한 화면 레이어를 구조화하면 아래와 같습니다.
이제 버튼도 잘 작동하게 되었습니다😀
css에서 부모 요소가 자식에게 상속되는 부분을 간과하는 경우가 많았습니다.
스타일이 기대한대로 적용되지 않았을 때, 개발자 도구를 통해 해당 요소에 적용된 스타일을 확인해보면
부모 요소가 미치는 영향 때문이라는 것을 자주 깨닫곤 했습니다.
(이번에도 어김없이 부모 요소의 영향으로 생긴 이슈였습니다,,ㅎㅎ)
그래도 이런 시행착오를 여러 번 겪다보니 오류를 잡아내는 속도가 점점 빨라지는 것을 느꼈습니다.
또한 이번 기회에 z-index를 제대로 활용해볼 수 있었습니다.
상대적으로 계산되는 요소를 잘 고려해서 레이어를 잘 구현하면
다양하고 심미적인 화면 구현이 가능하겠다는 생각이 들었습니다.
css는 오류메세지가 제공되는 것도 아니라서 안 풀릴 때 제일 답답하지만
제대로 구현되었을 때 디자인적으로 만족스러우면 그만큼 큰 재미도 느낄 수 있는 분야인 것 같습니다:)
즉석으로 이미지를 줄여주는 CDN 구축하기 (feat. Lambda@edge) (4) | 2024.10.27 |
---|---|
토스트 메세지 전역 컴포넌트로 관리하기 (0) | 2024.08.02 |
리액트에서 전역 상태로 모달 관리하기 (0) | 2024.07.30 |