고정된 돔 요소 위에서 모달 컴포넌트 구현하기

경이·2025년 1월 15일
0

📌 문제상황

실제 카카오 선물하기 서비스의 상품 상세조회 페이지

카카오 선물하기를 클론한 카카오 펀딩하기 프로젝트의 상품 상세 조회 페이지는 상품의 정보를 볼 수 있는 본문 영역과 상품의 수량과 옵션을 선택하는 옵션셀렉터가 수평으로 배치되어 있다. 오른쪽의 옵션 셀렉터는 고정되어 있다가 상품의 끝에 도달할 경우 옵션 셀렉터가 사라진다. 나는 이러한 UX가 불편하다고 판단하여 개선하고자 했다.

문제해결로 이동하기

시도 1. 옵션 셀렉터를 동적으로 움직이기

처음에는 사용자가 스크롤 할 때 옵션 셀렉터가 스크롤 된 y좌표를 동적으로 따라다니도록 코드를 구현했다. 그러나 옵션 셀렉터 하단의 펀딩 등록 버튼이나, 위시 버튼을 클릭할 때 마운트되는 모달이 bodypositionfixed로 변경시키면서 옵션 셀렉터가 다시 그려지고 y좌표를 유지가 어려운 상황이 발생했다.

이 문제를 해결하기 위해서 비슷한 UI를 사용하는 타사 쇼핑몰들을 참고해 보았지만, 대부분 모달 사용시 overflowhidden으로 적용하는 방법이 대부분이었다.

위처럼 모달이 마운트 될 경우 스크롤바 유무에 따라 화면이 움찔거리는 UX는 바람직하지 않다고 생각했다.

시도2. 옵션셀렉터를 고정하기

옵션 셀렉터의 positionfixed로 변경하고, useModal훅을 만들어 모달의y좌표와 모달 활성화 여부를 관리했다. 상태 값에 따라 모달이 마운트될 때 documentmodal의 스타일을 변경하여 모달과 옵션 셀렉터가 서로 영향을 받지 않도록 했다.

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 값을 키우더라도 버튼들이 푸터밑에 깔리게 되어 수정이 필요했다.

시도 3. Intersection Observer를 사용하여 스크롤 감지하기

이를 해결하기 위해 Intersection Observer API를 사용했다. 푸터 바로 위에 적당한 높이를 가지는 영역을 생성해 해당 영역이 Observer에 온전히 보이게 되면 옵션 셀렉터를 렌더링하지 않도록 하여 최종적으로 모달의 마운트에 따라 옵션 셀렉터 영향을 받는 문제를 해결할 수 있었다.

✏️ 느낀점

결국 처음에 문제라고 느꼈던 페이지 끝에 도달 시 옵션셀렉터가 사라지는 UX를 개선하지는 못했다. 하지만 위와 같은 과정을 통해 옵션 셀렉터와 모달이 서로 영향을 받지 않도록 하는 코드를 구현할 수 있었다. 이 경험을 통해 Intersection Observer API를 통해 화면에 보이는 영역을 감지하며 동적으로 UI 요소를 관리할 수 있게 되었고, 모달 구현에 대해 깊이 이해하게 되었다.

profile
록타르오가르

0개의 댓글