카카오 선물하기를 클론한 카카오 펀딩하기 프로젝트의 상품 상세 조회 페이지는 상품의 정보를 볼 수 있는 본문 영역과 상품의 수량과 옵션을 선택하는 옵션셀렉터가 수평으로 배치되어 있다. 오른쪽의 옵션 셀렉터는 고정되어 있다가 상품의 끝에 도달할 경우 옵션 셀렉터가 사라진다. 나는 이러한 UX가 불편하다고 판단하여 개선하고자 했다.
처음에는 사용자가 스크롤 할 때 옵션 셀렉터가 스크롤 된 y
좌표를 동적으로 따라다니도록 코드를 구현했다. 그러나 옵션 셀렉터 하단의 펀딩 등록 버튼이나, 위시 버튼을 클릭할 때 마운트되는 모달이 body
의 position
을 fixed
로 변경시키면서 옵션 셀렉터가 다시 그려지고 y
좌표를 유지가 어려운 상황이 발생했다.
이 문제를 해결하기 위해서 비슷한 UI를 사용하는 타사 쇼핑몰들을 참고해 보았지만, 대부분 모달 사용시 overflow
를 hidden
으로 적용하는 방법이 대부분이었다.
위처럼 모달이 마운트 될 경우 스크롤바 유무에 따라 화면이 움찔거리는 UX는 바람직하지 않다고 생각했다.
옵션 셀렉터의 position
을 fixed
로 변경하고, useModal
훅을 만들어 모달의y
좌표와 모달 활성화 여부를 관리했다. 상태 값에 따라 모달이 마운트될 때 document
와 modal
의 스타일을 변경하여 모달과 옵션 셀렉터가 서로 영향을 받지 않도록 했다.
const Modal = ({ onClose, children, className, isOpen, scrollPos }: ModalProps) => {
useEffect(() => {
const modal = document.getElementById('modal');
if (isOpen) {
document.documentElement.style.cssText = `
position: fixed;
top: -${scrollPos}px;
width: 100%;`;
modal!.style.cssText = `
z-index: 500;
position: fixed;
overscroll-behavior-y: contain;
inset: 0;
background: rgba(0, 0, 0, 0.4);
`;
}
return () => {
document.documentElement.style.cssText = '';
modal!.style.cssText = '';
window.scrollTo(0, scrollPos);
};
}, []);
return createPortal(
<div className={clsx(styles.wrapper_modal)} onClick={onClose}>
<div
className={clsx(styles.modal, className)}
onClick={(e) => e.stopPropagation()}
>
{children}
<button type="button" className={styles.btn_close} onClick={onClose}>
<span className={styles.ico_close}>닫기</span>
</button>
</div>
</div>,
document.getElementById('modal') as HTMLElement,
);
};
export default Modal;
그랬더니 옵션 셀렉터가 푸터를 덮는 문제가 발생했다. 물론 푸터의 z-index
가 옵션셀렉터보다 높기 때문에 발생하는 문제긴 했지만, 푸터의 z-index
값을 키우더라도 버튼들이 푸터밑에 깔리게 되어 수정이 필요했다.
이를 해결하기 위해 Intersection Observer API
를 사용했다. 푸터 바로 위에 적당한 높이를 가지는 영역을 생성해 해당 영역이 Observer
에 온전히 보이게 되면 옵션 셀렉터를 렌더링하지 않도록 하여 최종적으로 모달의 마운트에 따라 옵션 셀렉터 영향을 받는 문제를 해결할 수 있었다.
결국 처음에 문제라고 느꼈던 페이지 끝에 도달 시 옵션셀렉터가 사라지는 UX를 개선하지는 못했다. 하지만 위와 같은 과정을 통해 옵션 셀렉터와 모달이 서로 영향을 받지 않도록 하는 코드를 구현할 수 있었다. 이 경험을 통해 Intersection Observer API
를 통해 화면에 보이는 영역을 감지하며 동적으로 UI 요소를 관리할 수 있게 되었고, 모달 구현에 대해 깊이 이해하게 되었다.