웹뷰 엔지니어를 위한 iOS Webview Input 경험 개선기 (새 탭에서 열림)

당근 커뮤니티실의 웹뷰 엔지니어가 iOS 환경에서 키보드가 올라올 때 화면 전체가 위로 밀리는 고질적인 문제를 해결하기 위해 시도한 네 가지 단계의 여정을 담고 있습니다. iOS 웹뷰의 레이아웃(Layout) 및 시각적(Visual) 뷰포트 특성을 분석하고, 최종적으로 opacity 속성을 이용해 OS의 자동 스크롤 동작을 선제적으로 차단하는 최적의 사용자 경험(UX) 솔루션을 도출했습니다. 이는 기술적 완결성보다 유저의 입력 흐름을 깨지 않는 실전적인 해결책에 집중한 사례입니다.

iOS 웹뷰의 뷰포트 구조와 문제의 원인

iOS 웹뷰에서 입력창(Input)에 포커스가 되면 키보드 공간을 확보하기 위해 페이지가 위로 밀려 올라가는 현상이 발생합니다.

  • 두 가지 뷰포트의 차이: 키보드가 올라와도 크기가 변하지 않는 'Layout Viewport'와 사용자 눈에 보이는 영역인 'Visual Viewport' 간의 불일치가 원인입니다.
  • OS의 강제 동작: iOS는 포커스된 입력창을 시각적 영역 안에 두기 위해 페이지 전체를 밀어 올리며, 이 과정에서 상단 콘텐츠가 화면 밖으로 사라지는 등 웹 개발자가 제어하기 어려운 동작이 수반됩니다.

초기 시도: 리사이징과 오프셋 보정의 한계

문제를 인지한 후 화면을 원래 위치로 되돌리거나 밀린 만큼 따라가는 방식을 시도했으나 기술적 한계가 있었습니다.

  • Resize 방식: visualViewport의 변화를 감지해 래퍼 요소를 축소하고 scrollTo(0, 0)를 호출했으나, OS가 화면을 먼저 밀어버린 후 복구되기 때문에 화면 떨림과 깜빡임이 발생했습니다.
  • OffsetTop 방식: visualViewport.offsetTop 값을 계산해 화면이 밀린 만큼 레이아웃의 top 위치를 조정했습니다. 첫 번째 시도보다 나았지만, 키보드가 올라오는 과정에서 실시간 보정 딜레이로 인한 미세한 진동 피드백이 남았습니다.

전환점: Fake Input을 활용한 입력창 스왑

iOS가 화면을 밀어 올리는 원인 자체를 제거하기 위해 입력창을 두 개로 분리하는 전략을 세웠습니다.

  • 동작 원리: 평소에는 화면에 보이는 'Fake Input(ReadOnly)'을 노출하고, 터치 시 화면 밖에 숨겨둔 'Real Input'에 포커스를 줍니다.
  • 효과: iOS는 화면 밖에 있는 요소를 위해 스크롤을 발생시키지 않으므로 화면 밀림이 완벽히 해결되었습니다.
  • 문제점: 두 입력창 사이의 값(Value), 선택 영역, 자동 높이 조절 등을 동기화해야 하는 로직이 매우 복잡해져 유지보수 부담이 컸습니다.

최종 해결책: Opacity를 이용한 OS 속이기

입력창을 하나만 유지하면서도 OS의 자동 스크롤을 막기 위해 브라우저의 특성을 활용한 'Opacity Trick'을 적용했습니다.

  • 핵심 아이디어: iOS는 opacity: 0인 요소에 대해서는 'scroll-into-view'(포커스된 요소를 화면 안으로 가져오는 동작)를 수행하지 않는다는 점을 발견했습니다.
  • 구현 로직: onTouchStart 시점에 입력창의 opacity를 0으로 만들어 자동 스크롤을 차단한 뒤, focus가 완료되고 키보드가 올라온 시점에 다시 opacity를 1로 복원합니다.
  • 결과: 입력창 상태 관리의 복잡성 없이 단일 요소를 사용하면서도 화면 밀림 현상을 선제적으로 차단하여 가장 매끄러운 UX를 구현했습니다.

정석적인 API가 없는 환경에서 유저 경험을 위해 선택한 이 방식은 다소 'Hacky'할 수 있으나, 프로덕트의 핵심인 '글쓰기 경험'을 보호하기 위한 엔지니어링적 결단이었습니다. 기술적인 완벽함보다는 유저가 느끼는 불편함을 제거하는 것이 우선이며, OS 업데이트 등 변화하는 환경에 맞춰 지속적으로 해결책을 고도화해 나가는 자세가 중요합니다.