iOS 홈 화면 웹앱 채팅 하단 여백과 상태바 블러 수정 기록

- 아이폰 홈 화면에 설치한 웹앱에서 컴포저 아래 공백과 헤더 블러가 보여 네 개 티켓으로 수정했습니다.
- 하단은 h-dvh 대신 fixed inset-0을 쓰고 패딩과 마진을 조정했으며, 상단은 배경색 fixed 요소를 시도한 뒤 상태바 스타일을 default로 바꿨습니다.
- 빌드와 자동 테스트는 통과했지만 실기기 확인은 두 문제 모두 남아 있고, 티켓에도 미검증으로 적혀 있습니다.
katsubee 채팅을 아이폰 홈 화면에 설치해 쓰다 보니 PWA 화면의 위아래가 어색했습니다. 그래서 코드와 티켓 기록을 다시 읽으며 어디까지가 확인된 내용인지 구분해 보았습니다. 아래는 그 내용을 정리한 개발 기록입니다.
증상과 티켓 구성
보이는 문제는 두 가지였습니다. 컴포저 아래가 휑하게 비어 보였고, 헤더 영역은 흐릿하게 뭉개져 보였습니다. 하단 문제는 TB-256, 상단 블러는 TB-242에서 시작했고, 이후 TB-259와 TB-260이 각각 하단 간격 조정과 상태바 변경을 이어받았습니다.
채팅 루트는 안전 영역을 패딩으로 처리하는 구조였습니다. 상하좌우 모두 env(safe-area-inset-*)를 적용했고 높이는 h-dvh로 지정했습니다. 설치형 웹앱이라 브라우저 주소창이 없는데도 아래 간격이 컸습니다.
티켓에는 코드로 계산한 예상 간격이 46pt인데 스크린샷의 간격은 그보다 크다고 적혀 있습니다. 숫자가 맞지 않는다면 레이아웃 계산 어딘가가 어긋나 있다는 뜻이어서, 여기서부터 원인 추적이 시작되었습니다.
높이 단위 dvh를 의심한 하단 수정
먼저 의심한 것은 dvh입니다. 설치형 웹앱에서 dvh가 실제 화면보다 작게 계산되면 루트의 아래쪽이 비게 되고, 컴포저는 그 위에 떠 있는 것처럼 보입니다. TB-256 티켓도 이 가능성을 후보로 적었지만 dvh가 원인이라는 부분은 추정이라고 명시해 두었습니다.
해결 방향은 두 갈래였습니다. 높이 단위를 다른 것으로 교체하는 방법, 그리고 루트를 화면 전체에 고정하는 방법입니다. 커밋에 남은 쪽은 후자입니다.
// before
<div className="flex h-dvh w-full overflow-hidden ...">
// after
<div className="fixed inset-0 flex w-full overflow-hidden ...">
standalone 페이지 셸에도 같은 변경을 넣었습니다. 채팅 화면만 고치면 다른 화면에 똑같은 빈 띠가 남기 때문입니다. 컴포저 래퍼의 하단 패딩은 12에서 8px로 줄였고, 안전 영역 34px은 손대지 않았습니다.
고정 배치에는 부담이 따릅니다. 문서 흐름에서 빠지기 때문에 키보드가 올라올 때의 동작이 달라질 수 있습니다. 이 티켓의 검증 항목에는 모바일 E2E 39건 통과만 있고, 실기기에서 간격이 실제로 줄었는지는 비어 있습니다.
Gemini 화면을 참고한 모바일 간격 조정
TB-256과 같은 날 TB-259가 이어졌습니다. Gemini 화면을 레퍼런스로 놓고 모바일 레이아웃을 다듬었으며, 컴포저는 rounded-3xl 알약형으로 바꿨습니다. 하단 간격 목표는 약 26pt였습니다.
이 작업의 중심에는 루트가 이미 받아 둔 안전 영역 패딩을 음수 마진으로 일부 되돌리는 코드가 있습니다.
max-md:-mb-[max(0px,calc(env(safe-area-inset-bottom)-1.125rem))]
안전 영역에서 1.125rem을 뺀 만큼만 되돌리고, max로 묶어 0 아래로는 내려가지 않게 했습니다. 홈 인디케이터가 없는 기기에서는 마진이 0이므로 영향이 없습니다. 모든 변경은 md 미만에만 걸려 있어 데스크톱 화면은 그대로입니다.
같은 티켓에서 손본 곳이 몇 군데 더 있습니다.
- 전송 버튼에 shrink-0과 원형 클래스를 줘서 우측이 잘리던 문제를 풀었습니다.
- 모델명 라벨은 max-w-36에서 모바일 max-w-24로 줄였습니다.
- 인사 화면에는 컴포저를 아래로 내리는 max-md:mt-auto를 썼습니다.
- 헤더는 모바일에서 테두리를 없애고, 메뉴와 가이드 버튼을 44px 원형으로 키웠습니다.
상단 블러에 먼저 쓴 우회책
2026-10-16에 등록된 TB-242의 원인은 앱 코드에 있지 않았습니다. 티켓에는 iOS 27.0.1 설치형 웹앱이 black-translucent 상태에서 화면 상단에 가까운 콘텐츠에 시스템 블러를 입힌다고 적혀 있습니다. 직접 만든 블러 스타일을 걷어내는 방식으로는 해결할 수 없는 문제였습니다.
그래서 공개 보고에서 유일하게 동작한다고 알려진 방법을 가져왔습니다. 화면 상단 4px 이내에 배경색을 가진 fixed 요소를 두면 상태바가 그 색을 따라 단색이 된다는 내용입니다. 높이는 max(6px, safe-area-inset-top)로 잡았습니다.
<div aria-hidden="true"
className="pointer-events-none fixed inset-x-0 top-0 z-0
h-[max(6px,env(safe-area-inset-top))] bg-background" />
배경색은 테마 변수라서 라이트와 다크 모드에 맞춰 함께 바뀝니다. pointer-events-none을 줘서 터치 입력도 가로채지 않습니다. 메타 태그는 일부러 건드리지 않았습니다. 바꾸면 앱을 다시 설치해야 하는데 효과는 불분명했기 때문입니다. 같은 요소를 어드민 셸에도 넣었습니다.
우회책이 듣지 않아 상태바 스타일 변경
TB-259의 스크린샷을 보니 헤더 블러는 그대로였습니다. TB-260 티켓을 직접 열어 보니 바로 그 사실을 근거로 적고 있었습니다. 우회책은 실기기에서 효과가 없었다는 판단입니다.
2026-10-20에 등록된 TB-260은 접근 방식을 뒤집었습니다. 상태바 스타일을 black-translucent에서 default로 바꾼 것입니다. 상태바가 불투명한 영역이 되면 콘텐츠가 그 밑으로 들어가지 않으므로 블러를 받을 대상 자체가 사라집니다.
appleWebApp: { capable: true, title: "Katsubee",
statusBarStyle: "default" }
코드 변경은 한 줄로 끝납니다. 다만 이미 설치된 앱에는 적용되지 않아서 홈 화면에서 지우고 다시 설치해야 합니다. 배포 이후에도 이 절차를 모르는 사용자는 아무 변화도 느끼지 못합니다.
빌드와 테스트로 확인된 범위
자동화된 검증은 통과했습니다. TB-256은 모바일 E2E 39건이, TB-259와 TB-260은 next build가 통과했습니다. 어드민에 같은 우회 요소를 넣은 TB-242는 어드민 웹 248건과 core 프런트 빌드 통과가 기록돼 있습니다.
제품 문서에서는 모바일 항목에 TB-259, TB-256, 상태바 변경이 한 줄로 묶여 있습니다. 같은 문서의 PWA 항목에는 TB-242가 실기기 미검증 상태로 남아 있습니다.
실기기 검증이 남은 부분
세 티켓 모두 실기기 확인이 빠져 있습니다. 상태바가 불투명해지면 상단 안전 영역이 0이 되고, 그러면 TB-256과 TB-259에서 맞춘 상하 간격이 달라질 수 있습니다. 다크 모드에서 상태바 색이 배경과 어긋나는 경우에는 black-translucent로 되돌린다는 조건도 티켓에 적혀 있습니다.
하단 여백의 원인이 dvh라는 가설도 아직 증명되지 않았습니다. 다음에는 앱을 다시 설치한 기기에서 상단과 하단 간격을 한 번에 재고, 그 결과를 티켓에 적을 생각입니다.