iOS Safari에서만 화면이 깨질 때 비개발자가 먼저 볼 5가지
안드로이드와 PC에선 멀쩡한데 아이폰 사파리에서만 버튼이 안 눌리거나 입력창에서 화면이 확대된다면, 모바일 사파리 특유의 동작을 모르고 짠 코드일 가능성이 높습니다.
안드로이드 폰에서는 잘 보이고 데스크톱에서도 멀쩡한데, 아이폰 사파리에서만 화면이 어색하게 잘리거나 버튼이 안 눌린다는 제보를 받는 경우가 있습니다.
흔한 증상들:
- 화면 아래쪽 버튼이 주소창에 가려진다
- 입력창을 누르면 화면이 갑자기 확대된다
- position: fixed 로 띄운 모달이 키보드가 올라오면 위로 밀려 올라간다
- 안전영역(노치 주변)에 콘텐츠가 잘려서 보인다
이건 디자인 실수가 아니라, iOS Safari가 다른 브라우저와 다르게 동작하기 때문입니다. AI는 보통 Chrome 기준으로 코드를 짜기 때문에, 사파리 특유의 동작을 모르고 만든 코드가 그대로 나옵니다.
100vh가 사파리에서는 다르다
가장 자주 보이는 증상입니다. 화면 전체 높이를 100vh로 맞춰뒀는데, 아이폰에서는 화면 아래쪽 버튼이 주소창에 가려져 안 보이는 경우입니다.
이유는 사파리가 100vh를 "주소창이 사라졌을 때의 화면 높이" 로 계산하기 때문입니다. 실제 보이는 영역은 그보다 작은데도, 100vh를 그대로 쓰면 그 차이만큼 콘텐츠가 화면 밖으로 밀려납니다.
해결 방향은 두 가지입니다.
- 100vh 대신 100dvh (dynamic viewport height) 를 사용한다 — 최근 사파리는 이 값을 지원합니다
- 자바스크립트로 실제 화면 높이를 측정해 CSS 변수로 넣어둔다
비개발자라면 AI에게 "100vh를 쓰는 부분을 100dvh로 바꿔줘. 단, 필요하다면 fallback도 같이 둬줘" 라고 요청하는 게 가장 안전합니다.
input 폰트 크기가 16px 미만이면 화면이 확대된다
사파리는 input이나 textarea에 포커스가 갈 때, 그 글자 크기가 16px보다 작으면 화면을 자동으로 확대합니다. 사용자가 글자를 잘 읽을 수 있게 도와주려는 동작인데, 디자인 의도와는 자주 충돌합니다.
증상:
- 로그인 화면에서 이메일 입력창을 누르면 화면이 갑자기 확대됨
- 확대된 뒤 다시 원래대로 돌아오지 않아 가로 스크롤이 생김
- 입력 후 다른 곳을 눌러도 어색하게 줌이 풀리지 않음
해결책은 단순합니다. input, textarea, select의 font-size를 16px 이상으로 지정하면 자동 확대가 일어나지 않습니다.
작게 보이게 디자인하고 싶더라도, 폰트 크기 자체는 16px로 두고 transform: scale 같은 다른 방법으로 시각적으로만 줄이는 편이 안전합니다.
키보드가 올라오면 fixed 요소가 따라 움직인다
사파리는 키보드가 올라올 때 viewport 자체를 위로 밀어버립니다. 다른 브라우저처럼 키보드가 콘텐츠 위에 떠 있는 느낌이 아니라, 화면 자체가 짧아지면서 그 위에 그려지는 식입니다.
이 때문에 position: fixed 로 화면 하단에 붙여둔 버튼이 키보드와 함께 위로 올라와 입력 화면을 가립니다. 모달 안에서 input이 위로 사라지는 것도 같은 원인입니다.
완벽하게 해결하기는 까다롭지만, 자주 쓰는 회피 방법은 이렇습니다.
- 입력 중에는 fixed 버튼을 잠시 숨긴다
- 모달 안의 입력창은 키보드가 올라왔을 때 자동으로 스크롤되도록 처리한다
- visualViewport API를 써서 실제 보이는 영역을 추적한다
중요한 메시지를 반드시 화면에 붙여두고 싶다면, 차라리 위쪽에 띄우는 디자인이 사파리에서 안전합니다.
안전영역(노치, 홈바)에 콘텐츠가 잘린다
아이폰의 노치나 하단 홈바 주변은 사용자가 클릭하기 어려운 영역입니다. 사파리는 이 영역을 안전영역(safe area) 으로 표시하고, 디자인이 그 영역까지 침범하지 않게 비워두라고 권장합니다.
신경 쓰지 않으면 이런 증상이 생깁니다.
- 헤더가 노치에 잘려서 로고 일부가 안 보인다
- 화면 아래 버튼이 홈바와 겹쳐서 누르기가 어렵다
- 가로 모드에서 콘텐츠 양옆이 노치에 가려진다
CSS의 env(safe-area-inset-top), env(safe-area-inset-bottom) 같은 값을 padding으로 더해주면 자동으로 안전영역만큼 여백이 생깁니다. AI에게 "헤더와 풋터에 iOS 안전영역 padding을 적용해줘" 라고 요청하면 보통 이 방식으로 처리합니다.
추가로 head 태그 안에 viewport 메타에 viewport-fit=cover 가 들어 있어야 안전영역 값이 정상적으로 활성화됩니다.
tap-highlight와 sticky 동작
자잘하지만 자주 신고되는 증상이 두 가지 있습니다.
버튼을 누를 때 회색 박스가 잠깐 깜빡이는 현상은 사파리의 tap-highlight 기본 동작입니다. CSS에서 -webkit-tap-highlight-color를 transparent로 두면 사라집니다.
position: sticky 도 사파리에서 동작이 미묘하게 다릅니다. 부모 요소에 overflow가 hidden으로 걸려 있으면 sticky가 제대로 붙지 않고 스크롤과 함께 그냥 흘러가버립니다. "분명히 위에 붙어 있어야 하는데 같이 사라져요" 라는 증상이라면 부모의 overflow 설정을 의심하세요.
AI는 이런 사파리 특이 동작을 자주 놓칩니다. 그 결과 안드로이드에서는 잘 동작하는 코드가 아이폰에서만 어색해집니다. 증상을 캡처해서 "이 동작이 iOS Safari에서만 일어나는데, 사파리 특유의 동작 중 어떤 것이 원인일 가능성이 있는지 짚어줘" 라고 물어보면 비교적 정확한 답을 받을 수 있습니다.
테스트할 때의 팁
사파리 문제는 시뮬레이터로는 잘 안 잡힙니다. 가능하면 실제 아이폰에서 직접 확인해야 합니다.
비개발자가 쓸 수 있는 가장 빠른 방법:
- 아이폰에서 사이트를 연 뒤 문제가 일어나는 화면을 영상으로 녹화한다
- 화면 녹화에 키보드 올라오는 순간, 입력창 누르는 순간 같은 행동을 모두 담는다
- 동일한 흐름을 안드로이드와 데스크톱에서도 한 번씩 찍어 비교한다
이렇게 영상을 같이 보내면, 어느 단계에서 사파리 특유의 동작이 끼어드는지 빠르게 좁혀낼 수 있습니다. "안 돼요" 보다 "이 영상의 12초 부근에서 입력창을 누르면 이렇게 됩니다" 가 훨씬 빨리 풀립니다.
관련 글: AI로 만든 서비스를 개발자에게 맡기기 전 준비할 것, Lovable로 만든 사이트 수정이 안 될 때: 비개발자 체크리스트