팝업이 열릴 때 브라우저의 스크롤을 방지하기 위해 흔하게 사용하는 방법으로 css를 활용하여 body에 overflow:hidden을 적용 시킵니다. 방법도 간편하고 스타일로 제어할 수 있기 때문에 많이 사용하지만 ios safari에서 동작하지 않는 문제가 있기 때문에 추가적으로 작업을 해야합니다.
// 기존 팝업 스크롤 방지
const body = document.querySelector('body');
body.style.overflow = 'hidden'
여러 방법이 있지만 현재 가장 활용도가 높은 방법은 position을 활용하여 현재 이동한 스크롤의 높이값 만큼 body를 고정 시키는 방법입니다.
스크롤의 높이값을 구하는 건 window.pageYOffset를 활용하여 현재 페이지의 스크롤을 내린 만큼 값을 구할 수 있습니다. 추가로 설명을 하자면 window.pageYOffset은 scrollY와 똑같은 기능을 하지만 하위 브라우저도 지원을 하기 때문에 크로스 브라우징을 생각한다면 pageYOffset을 활용하는 것이 좋습니다.
// 현재 페이지에서 스크롤을 내린만큼 값을 저장
let scrollPosition = 0;
scrollPosition = window.pageYOffset;
해당 스크롤의 위치값을 구했다면 body의 position:fixed를 주고 위치 값을 지정할 때 top에 스크롤의 위치값 만큼 값을 빼줍니다. 값을 빼주지 않으면 top:0으로 되어 스크롤이 최상단으로 올라가게 처리 됩니다!
// 저장된 스크롤의 위치값 만큼 빼주자
const body = document.querySelector('body');
body.style.top = `-${scrollPosition}px`;
마무리로 body의 width:100% 설정(position:fixed가 설정 되면서 기존 display:block의 width값이 사라지기 때문)과 팝업을 닫을 때 설정 했던 css 속성 값을 삭제해주면 아래와 같은 코드가 됩니다.
const body = document.querySelector('body');
let scrollPosition = 0;
// 팝업 오픈
function enable() {
scrollPosition = window.pageYOffset;
body.style.overflow = 'hidden';
body.style.position = 'fixed';
body.style.top = `-${scrollPosition}px`;
body.style.width = '100%';
}
// 팝업 닫기
function disable() {
body.style.removeProperty('overflow');
body.style.removeProperty('position');
body.style.removeProperty('top');
body.style.removeProperty('width');
window.scrollTo(0, scrollPosition);
}
팝업을 닫을 때 보통 선언했던 css 속성을 초기화 시켜 원래 상태로 되돌리는데 removeProperty 메소드를 활용하면 초기화 시키지 않고 해당 스타일을 쉽게 제거할 수 있습니다. 그리고 마지막에 스크롤의 위치를 이동 시킬 수 있는 window.scrollTo(X축, Y축) 메소드를 활용하여 팝업 오픈때 저장한 스크롤의 위치값 만큼 스크롤을 이동시켜 body의 position이 해제 됐을 때 최상단으로 이동하는 걸 방지할 수 있습니다.
스크롤 잠금이 활성화 된 상태에서 브라우저 창의 크기를 변경하면 처음 저장 했던 스크롤의 높이와 달라 지기 때문에 스크롤 위치가 올바르게 복원되지 않는 단점이 존재합니다. 하지만 그 외에 사용 했을 때 문제점을 따로 발견하지는 못했습니다.
이 분 글 너무 잘쓰시네요.
저도 비슷한 방식으로 써봤었는데요.
iOS 모바일 Safari에서 fixed로 모달 팝업을 띄웠을 경우 해당 팝업 내부에 컨텐츠 자체 스크롤이 있을 경우
최상단 or 최하단 지점에서 바운스 동작이 먹은 뒤에 아예 컨텐츠 내부 스크롤이 동작 안하는 케이스가 있습니다.