Javascript/CSS 아이폰 iOS 사파리 웹브라우저에서 오류 해결하기 ~ 레이어팝업 스크롤 있는경우 페이지 스크롤 차단하기 등

안드로이드의 크롬계열 (크롬을 비롯해 네이버 웨일 등) 에서는 이상이 없는데 아이폰 iOS 사파리나, 아이폰 구글 검색 앱 (Google Search App) 등에서 문제가 생기는 UI 요소들이 있어 이를 해결하는 방법을 공유하고자 합니다. 특히 구형 아이폰(아이폰6 이하)이나 소프트웨어 업그레이드를 하지 않은 iOS 12.x 버전은 문제가 상당히 다양하게 나타납니다.

1. 아이폰 사파리에서는 iframe 이나 window.open() 을 사용하는 팝업 기능을 사용할 때 항상 주의해야 합니다.

만약 웹사이트 페이지에 iframe 이나 window.open() 을 사용한다면 안드로이드 크롬계열에서 보던것과 동일하게 동작할 것이라는 기대를 버리는게 좋습니다.

최선의 방책은 가능한한 iframe 이나 window.open() 을 사용하지 않는게 좋습니다.

iframe 의 경우 처음에는 잘 동작하는 것처럼 보일 수 있어서 특히 테스트를 많이 해보셔야 합니다.

팝업의 경우에는 해결책이 있습니다.

일단 아래와 같이 보통 많이 사용하는 방식의 코드를 보겠습니다.

// 평범하게 팝업창을 엽니다.
window.open('url...')
<script>
// 팝업창 쪽 코드
function closePopup() {
  window.close()
}
</script>

<button onclick="closePopup()">닫기</button>

위와같은 코드로 많이 사용하실 텐데 이렇게 하면 window.open()을 사용하는 팝업의 경우 팝업이 열리는 것까지는 괜찮지만 창닫기 시 창이 제대로 닫히지 않고 안드로이드처럼 opener 페이지로 제대로 되돌아 가지 않는 등의 문제가 생깁니다.

이를 해결하려면 아래와 같이 코드를 작성해야 합니다.

<script>
// 일단 평범하게 팝업창을 엽니다
let popupWindow = window.open('url')

// 팝업창을 닫을 함수를 window DOM 객체에 추가합니다. 
window.closePopupWindow = function () { 
  popupWindow.close()
}
</script>
<!-- 이제 팝업창 쪽에서의 코드입니다. -->
<script>

function closePopup() {
  opener.window.closePopupWindow()
}
</script>

<button onclick="closePopup()">닫기</button>

위와 같이 opener DOM 객체를 통해 팝업창을 호출한 쪽에 만들어두었던 함수에 자신을 닫도록 요청합니다. 이렇게 하면 아이폰계열에서도 정상적으로 팝업창을 닫을 수 있습니다.

2. 아이폰 사파리에서 레이어 팝업 기능(Bootstrap의 Modal 창이나 Vuetify 의 Dialog, Bottom Sheet 같은 기능)을 사용하는 경우 레이어 팝업에 스크롤이 들어 있다면 페이지 스크롤과 혼합되서 사용하기 불편한 UI가 될 수 있습니다.

사실 이 문제는 안드로이드 크롬계열에서도 잘 일어나는 문제인데요. 크롬쪽에서는 간단히 아래와 같이 css 만으로 혼합 스크롤을 방지하고 레이어 쪽 스크롤만 할 수 있도록 설정할 수 있습니다.

html, body { 
  overflow-y: hidden; 
} 

흑은 Vuetify 처럼 클래스를 만들어두고 레이어가 떴을 때만 클래스를 추가하고 레이어어를 닫으면 클래스를 제거해 원래 페이지 스크롤 기능을 회복하도록 하기도 합니다.

css 소스


html.overflow-y-hidden {
    overflow-y: hidden!important;
}

html 소스

<!DOCTYPE html>
<html class="overflow-y-hidden"> <!-- 다이얼로그가 떴을 때 html 태그에 이 클래스가 추가됩니다. 다이얼로그를 닫으면 이 클래스도 빠집니다. -->
...
<body style="overflow:hidden;"><!-- html 에서와 동일하게 동작 -->
...
</body>
</html>

안드로이드 크롬계열 브라우저는 이것만으로도 완벽하게 스크롤을 제어할 수 있어 간단히 해결할 수 있습니다.

하지만 아이폰 사파리는 이것만 가지고는 스크롤 제어가 되지 않습니다.

여러가지 찾아봤지만 가장 간단하고 확실하게 해결할 수 있는 방법은 body-scroll-lock 자바스크립트 라이브러리를 이용해서 해결하는 방법입니다.

간단히 Vue + Vuetify 를 이용한 예제를 보여드리겠습니다.

아래는 버그가 있는 버전입니다. 아이폰 사파리나 아이폰 구글검색앱에서 확인가능합니다. OPEN DIALOG 버튼을 클릭해 다이얼로그창이 뜨면 다이얼로그 내의 스크롤을 해보시기 바랍니다. 어느순간부터 아래 페이지가 마음대로 스크롤되는 것을 볼 수가 있습니다. 스크롤이 완전히 멈출때까지는 계속 페이지 스크롤만 되버리니 사용자가 느끼기에 매우 불편한 UI가 되버립니다.

https://github.com/dooglegh/body-scroll-lock-example/blob/master/body-scroll-lock-bug.html

이제 이 문제를 해결한 버전입니다. 다이얼로그가 뜰대 bodyScrollLock.disableBodyScrool() 을 호출해 스크롤하고 싶은 영역의 DOM 엘레멘트를 지정해 주면 됩니다. 반대로 닫을 때 bodyScrollLock.enableBodyScrollLock() 을 호출하시면 페이지 스크롤이 가능해집니다.

https://github.com/dooglegh/body-scroll-lock-example/blob/master/body-scroll-lock-example.html

3. 아이폰 iOS 사파리에서 스크롤 시 발생하는 출렁이는 효과 (bounce effect) 없애기

아이폰에는 화면 스크롤시 페이지 끝에 도달하면 끝부분이 출렁거리는 효과를 주는데요. 이걸 없애야 하는 경우가 있습니다. 대표적으로 Vuetify 의 Bottom Sheet 컴포넌트 인데요. 기본적으로는 사용할 때 이상이 없지만 2번과 마찬가지로 스크롤 가능한 요소를 컴포넌트 안에 넣으면 스크롤시 출렁이는 효과가 발생하고 사용하기 경박스러운(?) 느낌이 듭니다. 이를 해제하기 위해서는 스크롤 요소 (즉 높이를 지정한 요소를 말합니다.) 에 -webkit-overflow-scrolling 스타일을 auto 로 넣어주면 됩니다.

-webkit-overflow-scrolling 에 대한 자세한 설명은 https://developer.mozilla.org/ko/docs/Web/CSS/-webkit-overflow-scrolling 를 참조하시기 바랍니다.

맺으며..

과거에는 마이크로소프트의 인터넷 익스플로러 때문에 골치가 아팠는데.. 요새는 아이폰 사파리 때문에 흰머리가 느는 거 같네요. 아무튼 해결못할 문제는 없으니 다들 힘내시기 바랍니다. ^^