Framework/React & RN

[Hooks] 모달 띄웠을 때 스크롤을 막는 방법

Joonfluence 2022. 4. 15. 14:35

오늘은 모달이 떠있는 상태에서 스크롤이 안되도록 처리해보겠습니다. 방법은 아주 간단합니다! 모달을 띄울 때, body의 style로 overflow hidden을 주면 됩니다. 반대로, 모달을 닫을 땐 overflow 속성을 지워주면 되겠죠?

import { useCallback } from 'react';

export function useBodyScrollLock() {
  const lockScroll = useCallback(() => {
    document.body.style.overflow = 'hidden';
  }, []);

  const openScroll = useCallback(() => {
    document.body.style.removeProperty('overflow');
  }, []);

  return { lockScroll, openScroll };
}

모달 컴포넌트가 작성되어 있는 상황을 가정해봅시다. 그러면 코드는 아래와 같아지겠죠.

const Component: FC<Props> = ({ label, imageSource }) => {
  const [isOpen, setIsOpen] = useState(false);
  const { lockScroll, openScroll } = useBodyScrollLock();

  const handleOpen = () => {
    lockScroll();
    setIsOpen(true);
  };

  const handleClose = () => {
    openScroll();
    setIsOpen(false);
  };

  return (
    <div>
      <div onClick={handleOpen}>
        <img
          src={imageSource}
          alt={label}
        ></img>
      </div>
      <span>{label}</span>
      {isOpen && (
        <Modal
          isOpen={isOpen}
          handleClose={handleClose}
        />
      )}
    </div>
  );
};

단순하게 위 코드로만 테스트했을 때, IOS Chorome/Safari에선 overflow hidden이 정상적으로 작동되지 않는 문제가 있었습니다. 따라서 스크롤이 되지 않도록 처리하는 코드를 추가해줘야 하는데요. 아래와 같이, position fixed를 주고, top 위치로 사용자가 스크롤한 위치만큼 -로 계산해주는 것입니다. 그러면 overflow 속성 없이도 스크롤을 막아줄 수 있습니다.

import { useCallback } from 'react';

export function useBodyScrollLock() {
  let scrollPosition = 0;
  const lockScroll = useCallback(() => {
    // for IOS safari
    scrollPosition = window.pageYOffset;
    document.body.style.overflow = 'hidden';
    document.body.style.position = 'fixed';
    document.body.style.top = `-${scrollPosition}px`;
    document.body.style.width = '100%';
  }, []);

  const openScroll = useCallback(() => {
    // for IOS safari
    document.body.style.removeProperty('overflow');
    document.body.style.removeProperty('position');
    document.body.style.removeProperty('top');
    document.body.style.removeProperty('width');
    window.scrollTo(0, scrollPosition);
  }, []);

  return { lockScroll, openScroll };
}

이상으로 설명을 마치겠습니다. 읽어주셔서 감사합니다!

반응형