개발지식

[IOS] 웹앱 환경에서 키보드가 화면을 가린다면?

weaklion 2023. 8. 17. 16:34

최근 하이브리드 앱 때문인지 네이티브 앱에 웹 페이지를 포팅하는 웹앱 개발이 늘어나고 있습니다.

지금 제가 개발하고 있는 프로젝트 같은 경우에도, 안드로이드는 코틀린, ios는 swift로 작성한 네이티브 환경에 vue3, typescript로 작업한 페이지를 띄어주는 형식으로 작업하고 있죠.

코틀린과 swift는 다른 네이티브 개발자가 개발하고, 저는 웹 페이지의 프론트엔드를 개발하는 방식입니다.

그러다 보니 웹 페이지를 개발하지만, 모바일을 우선으로 개발해야만 합니다. 반응형 디자인은 기본적으로 깔고 가되, 안드로이드와 ios 환경에서의 ux를 항상 고민해야만 한다는 거죠.

가령 안드로이드는 뒤로가기 버튼이 존재하지만, ios는 스와이프를 해야만 뒤로가지기 때문에, 다른 사용자 경험을 보여주어야만 합니다.

게다가 안드로이드와 ios는 input 혹은 textarea에 focus가 될 때에 페이지를 차지하는 방식이 확연히 다릅니다.

자세한 건, 아래를 참조해주세요. 채널톡에서 어떻게 ios의 크로스 브라우징을 대처했는지에 대해 잘 나와있습니다.

https://channel.io/ko/blog/cross_browsing_ios15

 

iOS15 대응기(feat. 크로스 브라우징)

2021년 9월 20일에 iOS15가 업데이트 되었습니다. 이번 릴리즈에는 Safari 브라우저에서 아주 큰 변화가 있었어요. 바로 브라우저 내의 주소창이 아래로 이동이 되었다는점! 채널톡은 위처럼 고객이

channel.io

간략하게 설명하면 안드로이드는 키보드가 열릴 때 viewport를 키보드를 제외한 영역만큼의 height를 설정해주지만, ios는 그런 거 없이 그냥 document를 keyboard영역 만큼  강제로 끌어 올립니다.

이 과정에서 웹 페이지, 혹은 안드로이드에서 정상적으로 출력되는 화면이 ios는 깨지게 되는 경우가 많죠. 

그래서 ios에서는 따로 input에 focus가 됐을 시, 스크롤을 설정해주어야만 합니다.

 

사실 네이티브에서 keyboard 크기를 알 수 있어 그 만큼 스크롤 하는 게 더 빠를지도 모릅니다. 그런데 네이티브가 아닌 페이지에서 해결해야할 때도 생기죠.

그게 언제냐? 네이티브 개발자가 때려치우고 나갔는데, 갑자기 강도가 와서 목에 칼을 들이밀면서 키보드를 해결해달라고 할 때 입니다. 

물론 그런 일은 생기지 않습니다. 사실 정확하게 말하면 네이티브에선 해결할 수 없어, 웹 페이지 단에서 해결해야 할 때죠.

 

웹에선 keyboard의 height를 알 수 없습니다. 따라서 우리는 페이지 전체의 height와, visualViewport의 height를 이용해서 이 문제를 해결할 예정입니다.

let prevVisualViewport = 0;
const handleVisualViewportResize = () => {
  if (isIos && modal_opened) { //ios인 상태에서 모달이 오픈되면
    const currentVisualViewport = window.visualViewport.height; //visualViewPort의 height를 가져옵니다.
    if (currentVisualViewport < prevVisualViewport) {
      const scrollHeight = window.document.scrollingElement.scrollHeight;
      const scrollTop = scrollHeight - window.visualViewport.height;

      window.scrollTo({ top: scrollTop, behavior: 'smooth' }); // 입력창이 키보드에 가려지지 않도록 조절
    }

    prevVisualViewport = window.visualViewport.height;
  }
 };

if (isIOS) {
  window.visualViewport.onresize = handleVisualViewportResize;
  //visualViewPort가 변경될 때 마다 호출
}

 

ios는 input에 focus가 되면 keyboard가 호출되지만, 안드로이드는 resize이벤트를 통해 호출됩니다. 위의 코드는 ios상에서 이슈가 생겼을 때에 만든 코드로 페이지 전체의 height에서 visualViewport의 height을 빼서 그만큼 스크롤 합니다. 

 

isIos는 지금 실행하고 있는 환경이 ios, android인지를 확인하는 함수입니다. userAgent를 통해서 간단히 구현할 수 있습니다.

 

말이 길었는데, 결론은 웹앱 환경에서 input에 focus가 됐을 때 해결하는 방법은 스크롤을 이용하는 것 입니다. visualViewport와 scrollHeight을 통해 임시적으로 해결할 수 있지만, 키보드의 정확한 height는 알 수 없기에 가장 좋은 건 네이티브에서 키보드의 height를 구해서 그만큼 화면을 올리는 게 가장 좋은 방법입니다.