프로젝트를 진행 중 만들기 모달을 만들다가 스크롤 하는 과정에서 배경화면이 스크롤 되어 아주 거슬리는 부분이 있었다.
그래서 진행하던 중 약 2가지 방법을 찾아냈다.
useEffect(() => {
document.body.style.cssText = `
position: fixed;
top: -${window.scrollY}px;
overflow-y: scroll;
width: 100%;`;
return () => {
const scrollY = document.body.style.top;
document.body.style.cssText = ``;
window.scrollTo(0, parseInt(scrollY || "0", 10) * -1);
};
}, [])
하나하나 설명해 보자면 일단 useEffect
를 통해 모달창이 렌더링 즉 마운트 될때 body
css를 변경시킨다.
실행 될 때body
값이 fixed
로 고정되며 top
이 현재 보고 있는 스크롤에 붙을 수 있도록 window.scrollY
로 현재 보고 있던 위치에 고정한다
overflow-y
를 scroll
로 놓아 스크롤이 사라져 화면 비율이 변하는 것을 막는다.
이후 return
(clean up
함수로 useEffect
를 정리해준다. deps
가 비어있으니 컴포넌트가 사라질 때 동작)을 통해 모달 창에 사라질 때 미리 스크롤링 하던 현재 바디 위치를 미리 scrollY
에 저장하고 body
의 css를 비워준다.
(위의 예제는 빈 값이지만 나는 body에 정한 css가 있었어서 해당 css로 변경시켰다.)
이후 window.scrollTo
를 이용해 모달이 종료되었을 때 해당하는 스크롤에 그대로 있을 수 있게 한다.
출처: 스크롤 고정 출처
import { useRef } from "react";
export default () => {
const scroll = useRef(false);
const blockScroll = () => {
if (typeof document === "undefined") return;
const html = document.documentElement;
const { body } = document;
if (!body || !body.style || scroll.current) return;
const scrollBarWidth = window.innerWidth - html.clientWidth;
const bodyPaddingRight =
parseInt(
window.getComputedStyle(body).getPropertyValue("padding-right")
) || 0;
/*
* 1. iOS 및 데스크톱 사파리의 버그 수정으로 설정 {overflow: hidden}은
* html/body에서 스크롤을 방지하지 않는다. *
* 2. {overflowY}가 방지하지 않는 데스크톱 사파리에서 버그 수정 *
* {overflow-x} 스타일이 본문에도 적용되는 경우 스크롤
*/
html.style.position = "relative"; /* [1] */
body.style.position = "relative"; /* [1] */
html.style.overflow = "hidden"; /* [2] */
body.style.overflow = "hidden"; /* [2] */
body.style.paddingRight = `${bodyPaddingRight + scrollBarWidth}px`;
scroll.current = true;
};
const allowScroll = () => {
if (typeof document === "undefined") return;
const html = document.documentElement;
const { body } = document;
if (!body || !body.style || !scroll.current) return;
html.style.position = "";
html.style.overflow = "";
body.style.position = "";
body.style.overflow = "";
body.style.paddingRight = "";
scroll.current = false;
};
return [blockScroll, allowScroll];
};
앞서 useEffect
를 사용한 것과 내용은 거의 비슷하다. 똑같이 body와 html을 구한 후 css들을 변경하여 진행한 것이다.