pile·
프론트엔드·카카오 엔터테인먼트 FE카카오 엔터테인먼트 FE·

사파리, 모바일 환경에서의 트러블슈팅

IE 지원 종료 이후 자리를 물려받은 사파리와 모바일 환경의 동작 차이를 네 가지 사례로 짚고 증상과 원인, 해결책까지 붙인 글이다. PC 크롬으로 개발하다 보면 놓치는 것들이라 사례마다 재현 코드가 함께 있다. 남이 찾은 해결책을 그대로 붙이지 말고 내부 동작을 보라는 것이 저자의 태도다.

핵심 포인트
  • 스크롤 컨테이너 내부 요소가 지워질 때 크롬은 지워진 높이만큼 scrollTop을 빼지만 사파리는 그대로 둔다.
  • userAgent로 브라우저를 판별해 분기하지 말고 그 동작이 나타나는지를 조건으로 삼아야 한다.
  • 사파리에서 스크롤 영역이 있으면 회전 시 그 영역이 독자적인 레이어로 합성돼 절대 위치 요소가 가려진다.
  • iOS의 스크롤 관성 중에 scrollTop을 바꾸면 관성이 멈출 때 값이 되돌아간다.
  • touchend에서 요소를 숨기면 더블탭 판별 지연 뒤에 그 자리의 다른 요소가 클릭된다.
상세 정리
  • 배경: 브라우저 엔진이 WebKit, Blink, Gecko 셋으로 갈리는데 크롬 계열은 모두 Blink를 쓰고 버그 대응도 빠른 편이라, 점유율 20% 수준인 사파리에서만 나는 버그가 QA에 자주 올라온다.
  • 사례 1 증상: 스크롤을 중간까지 내려 scrollTop이 120인 상태에서 높이 100인 앞쪽 요소를 지우면 크롬은 20으로 줄이고 사파리는 120을 유지한다.
  • 사례 1 해결: 삭제 전후의 scrollTop과 scrollHeight를 재서 scrollTop이 그대로면 scrollHeight 변화량만큼 직접 더해 크롬 방식을 강제한다.
  • 분기 기준에 대한 조언: 사파리 판별은 오차가 있고 다른 브라우저에서도 같은 동작이 나올 수 있으므로 환경이 아니라 동작을 조건으로 잡는다.
  • 같은 원리의 확장: 접이식 기기 전용 버그도 모델을 판별하지 말고 미디어 쿼리의 min-width나 orientation처럼 기기의 특징으로 다루면 되는 경우가 많다.
  • 사례 2 증상: 회전 컨테이너 안에 스크롤 영역과 절대 위치 요소가 함께 있을 때, 회전 후 크롬은 절대 위치 요소가 계속 위에 있지만 사파리는 스크롤 영역이 그 위를 덮는다.
  • 사례 2 조건: 스크롤 영역의 overflow scroll을 없애면 재현되지 않고 두 브라우저가 같게 동작한다.
  • 사례 2 원인 추적: 사파리 개발자 도구 타임라인으로 보면 스크롤이 없을 때는 회전 시 전체 영역을 한 번 페인트하지만, 스크롤이 있으면 컨테이너와 스크롤 요소와 스크롤바 영역을 따로 다시 페인트한다. 절대 위치 요소는 별도 페인트 영역으로 잡히지 않는다.
  • 사례 2 레이어 확인: 회전 전에는 절대 위치 요소가 가장 앞이지만 회전 후에는 2D transform 영역에 포함되고, 스크롤 요소가 별도 레이어로 합성돼 앞으로 나온다.
  • 사례 2 해결: 가려지는 요소에 transform translate3d 0을 주거나 will-change transform을 주어 합성에 쓰일 독립 요소로 만들면 회전 후에도 순서가 유지된다.
  • 사례 3 증상: 스크롤을 움직이다 최하단 이동 버튼을 누르면 PC 크롬은 정상인데 iOS에서는 내부 요소가 아예 보이지 않고, 다시 스크롤해야 최하단에 있는 것이 보인다.
  • 사례 3 원인: iOS는 버튼을 누른 직후 scrollTop이 최하단으로 바뀌었다가 관성 움직임이 멈추는 시점에 스크롤 도중의 값으로 한 번 더 덮인다. 스크롤이 완전히 멈춘 뒤 누르면 재현되지 않는다.
  • 사례 3 해석: 관성은 제한된 화면에서 반복 드래그를 줄여주는 터치 기기의 UX 장치이므로 환경마다 UI 동작이 다를 수 있다는 점을 감안해야 한다.
  • 사례 3 해결: scrollTop을 바꾸기 직전에 overflowY를 hidden으로 껐다가 바꾼 뒤 다시 scroll로 되돌려 관성을 끊는다.
  • 사례 4 증상: 겹쳐 놓은 두 버튼 중 위 버튼의 touchend에서 자신을 숨기면 아래 버튼의 mousedown과 click까지 발생한다.
  • 사례 4 원인: touchend 직후가 아니라 더블탭 제스처 판별을 위한 지연 뒤에 click이 발생하는데, 그 사이 위 요소가 사라져 같은 좌표의 아래 요소가 대상이 된다.
  • 사례 4 해결: touchend 대신 click 이벤트에서 숨기면 된다. touchend 시점에 DOM 상태를 바로 바꾸는 것 자체가 부작용을 부른다.
  • 마무리 견해: 크로스 브라우징 e2e 테스트가 있어도 모든 환경을 사이클에 넣는 것은 부담이고 재현 조건이 복잡하면 잡히지 않는 경우가 많아, 결국 원인을 들여다본 경험이 쌓여야 한다고 본다.
왜 읽나크롬에서만 검증하고 배포했다가 사파리나 iOS에서 스크롤·레이어·터치가 어긋난 적이 있다면 네 가지 전형적인 패턴과 그 우회법을 미리 알아둘 수 있다.
카카오 엔터테인먼트 FE
카카오 엔터테인먼트 FE 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 프론트엔드·여기어때 (GC컴퍼니)여기어때 (GC컴퍼니)·

    항공 프론트엔드 구축기 (7/10): 창구를 하나만 두었습니다

    여기어때 항공 서비스 프론트엔드가 웹과 앱 웹뷰 두 환경에서 동일한 함수 호출로 동작하는 앱 브릿지 추상화 레이어를 설계한 과정을 다룬다. iOS·안드로이드 규약 차이와 "웹에 존재하지 않는 브릿지를 어떻게 호출하나"라는 문제를 단일 추상화 층으로 해결한 구현 사례다.

    요약 이어보기
    #react#typescript#webview+2