모달 팝업이 표시될 때 브라우저 스크롤을 막는 방법

브라우저 스크롤이 있는데 모달팝업의 내부 스크롤도 있는 경우, 모달팝업의 내부 스크롤을 마우스로 내리다가 끝에 다다르면, 브라우저 스크롤이 내려간다. (어둡게 처리된 내용이 스크롤되는 현상)

이런 현상을 막기위해 모달팝업이 표시될 때는 body의 overflow를 hidden으로 변경해서 브라우저 스크롤을 없에는 방법을 사용했더니, 브라우저 스크롤바가 사라지면서 그만큼 브라우저의 가로 길이가 늘어나면서 body의 컨텐츠가 움찔하면서 새로 확보된 공간만큼 재배치가 일어난다. 모달팝업이 닫히고 다시 브라우저 스크롤바가 생기면 반대방향으로 움찔하는 현상이 일어난다.
https://stackoverflow.com/questions/29897300/disable-scroll-on-body-when-modal-view-is-opened

이런 현상을 막기위해 body의 position을 fixed로 만들고, overflow를 scroll로 변경해서 스크롤바 영역은 남기지만 실제로 스크롤은 되지 않도록 하는 방법도 있다. 하지만 바닥의 스크롤이 맨위로 올라가버리는 부작용이 있고, 바닥의 스크롤바가 없는 경우에는 오히려 불필요하게 스크롤바가 표시되는 문제가 있다.

body의 스크롤을 일으키는 이벤트를 모두 막아버리는 방법도 있다. 하지만 컨텐츠가 스크롤되는 경우는 마우스 휠뿐만이 아니라 키보드의 화살표입력, 터치 이벤트, 마우스의 가운데 버튼을 클릭하고 움직이는 경우 등 모든 것을 제어하기가 쉽지 않다.

가장 코드가 깔끔하고도 동작이 정확한 방법은 body의 스크롤바를 없에고 자식들에게만 스크롤바를 만들어주는 것이다. javscript 없이도 css만으로 원하는 상태를 만들 수 있고, 바닥의 스크롤바의 표시여부와 스크롤 위치도 보존되는 방법이다.
https://stackoverflow.com/a/20028988/1896415

body를 브라우저 꽉차게 만들어서 스크롤바가 생기지 않게 만들고
body 하위에 바닥용 div와 모달팝업용 div를 자식으로 만들고
바닥용 div (아래 예시의 .content)는 스크롤바를 생기게 만들고
모달팝업용 div (아래 예시의 .modal-background)는 스크롤바를 생기지 않게 만든다.

모달팝업이 화면을 꽉 채우기 떄문에 스크롤이 위나 아래에 닿아도 부모 body로만 스크롤 이벤트가 올라가기 때문에 body의 자식인 바닥용 div는 스크롤되지 않는다.

https://jsfiddle.net/2kx2kmch/

<!DOCTYPE html>

<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>모바일 스크롤 막기</title>
<style type="text/css">
*{
margin:0;
padding:0;
}

.cont {
font-size: 30px;
font-weight: bold;
line-height: 330px;
text-align: center;
}
.cont1 { background-color: #F29B76; }
.cont2 { background-color: #EA68A2; }
.cont3 { background-color: #32B16C; }
.cont4 { background-color: #556FB5; }
.nav {
overflow: hidden;
overflow-y: scroll;
position: fixed;
top: 0;
left: 0;
z-index: 200;
width: 200px;
height: 100%;
border: 2px solid #000;
background: #fff;
}
.nav .menu {
display: block;
height: 70px;
margin-top: 20px;
background-color: #EA68A2;
}
button {
position:fixed;
top:0;
right:0;
z-index:100;
width:100px;
height:50px;
}
.bnt_open { right:110px; }

/* 바디에 스크롤 막는 방법 */
.not_scroll{
position: fixed;
overflow: hidden;
width: 100%;
height: 100%
}
.not_scroll .cont {
position: relative;
top: 0;
}
</style>

</head>
<body>
<button type="button" class="bnt_open">메뉴보기</button>
<button type="button" class="bnt_close">메뉴닫기</button>
<div style="display:none" class="nav">
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
<a class="menu">menu1</a>
</div>
<div class="cont cont1">content1</div>
<div class="cont cont2">content2</div>
<div class="cont cont3">content3</div>
<div class="cont cont4">content4</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js">
</script>
<script>
    var posY;

    $(".bnt_open").on("click", function(e){
        posY = $(window).scrollTop();

        $("html, body").addClass("not_scroll");
        $(".nav").css("display","block");
        $(".cont").css("top",-posY);
    });

    $(".bnt_close").on("click", function(){
        $("html, body").removeClass("not_scroll");
        $(".nav").css("display","none");
        posY = $(window).scrollTop(posY);
    });

</script>

</body>
</html>