forked from CodeitPart3/thejulge
-
Notifications
You must be signed in to change notification settings - Fork 0
useRemoveTopPageScroll
이토 edited this page Jun 1, 2025
·
2 revisions
모바일 환경에서 모달을 띄우거나 특정 레이어를 오버레이할 때, 배경 콘텐츠가 여전히 스크롤 가능해 UI가 흔들리거나 클릭이 오작동하는 문제가 있었습니다.
특히 모바일 디바이스에서 페이지 최상단 요소에 대해
overflow-hidden 클래스를 조건부로 적용해도,
디바이스 리사이즈 상황(회전 포함)에서는 스크롤이 여전히 남는 버그가 발생했습니다.
이는 단순한 스타일 이슈가 아닌, UX의 일관성과 안정성에 영향을 주는 문제로 판단했습니다.
이 문제를 해결하기 위해 다음과 같은 구조적 접근을 설계했습니다:
- 디바이스 타입 감지 훅 추출 (useBreakpoint)
뷰포트의 너비를 감지해 mobile, tablet 등 디바이스 타입을 반환하도록 훅을 정의하고, resize 이벤트 시에도 반응하도록 debounce를 적용하여 불필요한 렌더링을 방지했습니다.
// useBreakpoint.ts
function useBreakpoint(): DeviceType {
const [device, setDevice] = useState<DeviceType>(() =>
getDeviceType(window.innerWidth),
);
useEffect(() => {
const handleResize = debounce(() => {
setDevice(getDeviceType(window.innerWidth));
}, 200);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return device;
}
export default useBreakpoint;- 조건 기반 스크롤 제어 훅 구현 (useRemoveTopPageScroll)
condition과 observeDevices를 파라미터로 받아, 특정 디바이스 + 조건이 모두 만족될 때만 body에 overflow-hidden 클래스를 적용하거나 제거하도록 구현했습니다.
// useRemoveTopPageScroll.ts
interface UseRemoveTopPageScrollParams {
condition: boolean;
observeDevices: DeviceType[];
}
function useRemoveTopPageScroll({
observeDevices,
condition,
}: UseRemoveTopPageScrollParams) {
const device = useBreakpoint();
useEffect(() => {
const deviceCondition = observeDevices.includes(device);
if (condition && deviceCondition) {
document.body.classList.add("overflow-hidden");
} else {
document.body.classList.remove("overflow-hidden");
}
}, [device, condition, observeDevices]);
}
export default useRemoveTopPageScroll;// 실제 사용 예시
useRemoveTopPageScroll({
observeDevices: ["mobile"], // mobile 크기인지 감시
condition: showDropdown, // showDropdown이 true일 때, 최상단 엘리먼트의 스크롤이 제거 (overflow: hidden)
});- 훅으로 추상화하여 전역 적용 가능하도록 설계 페이지나 모달 컴포넌트 내부에서 반복되지 않도록, 명확한 조건만 주면 어디서든 동일한 스크롤 제어 로직을 재사용할 수 있는 구조로 만들었습니다.
- 모바일 및 태블릿 디바이스에서 스크롤 이슈가 안정적으로 제거되어 사용자 인터랙션이 자연스럽게 유지됨
- useRemoveTopPageScroll을 통해 페이지, 모달, 바텀시트 등 다양한 상황에 일관된 방식으로 스크롤 제어 가능
- 스크롤 방지 조건이 명시적으로 드러나 유지보수가 쉬워졌고, 디바이스 대응 로직도 중앙에서 관리 가능해졌음