아직도 100vh 쓰세요?

아린·2026년 4월 15일
post-thumbnail

모바일 웹뷰의 100vh 이슈와 dvh / svh / lvh 대응

📝 TL;DR

모바일에서 100vh는 주소창 UI에 따라 들쭉날쭉해서 풀스크린을 보장하지 못한다. 이젠 dvh / svh / lvh를 써라. 기존 --vh JS 해킹은 CSS 한 줄로 치환 가능.

🔍 상세

배경 / 동기

모바일 웹뷰에서 height: 100vh를 주면 스크롤할 때 레이아웃이 튄다. 기대치는 "화면 꽉 차게"인데, iOS Safari와 일부 안드로이드 Chrome은 주소창이 나타났다 사라지는 동안 뷰포트 높이가 바뀐다. 100vh주소창이 숨겨진 상태(=최대 높이) 기준으로 고정돼있어서, 주소창이 나와 있는 동안은 실제 보이는 영역보다 100vh가 더 크다. 결과적으로 하단 요소가 주소창에 가려지거나, 스크롤 시 화면이 덜컥거린다.

내용

CSS Values and Units Level 4에서 뷰포트 단위가 네 계열로 세분화됐다.

단위의미언제 씀
vh기존 단위 (브라우저별 해석 차이 있음)레거시 호환
lvhLargest — 주소창 숨겨졌을 때 기준"제일 넓을 때" 기준이 필요할 때
svhSmallest — 주소창 보이는 상태 기준"절대 잘리지 않아야" 할 때
dvhDynamic — 현재 보이는 영역 실시간 반영대부분의 실무 케이스
/* 풀 스크린 섹션 — 주소창에 가려지지 않게 */
.hero {
  min-height: 100svh;   /* 주소창 나와도 안 잘림 */
}

/* 스크롤에 따라 자연스럽게 맞추고 싶을 때 */
.fullscreen-modal {
  height: 100dvh;       /* 스크롤에 맞춰 갱신됨 */
}

/* fallback 포함 권장 */
.safe {
  min-height: 100vh;    /* 구형 브라우저용 */
  min-height: 100dvh;   /* 지원되면 덮어씀 */
}

너비 쪽도 dvw / svw / lvw가 짝으로 존재한다. 대부분은 높이가 문제라 덜 쓰는 편.

주의할 점

  • dvh는 자주 갱신된다 — 스크롤 중 실시간으로 레이아웃이 다시 계산되므로 height: 100dvh를 무거운 컨테이너에 걸면 성능 저하가 느껴질 수 있다. Safari에서 특히 덜컥임 보고가 있다.
  • position: fixed 요소 주의fixed; bottom: 0 요소는 dvh를 쓰지 않으면 주소창 변화에 따라 잘린다.
  • iOS WKWebView 버전별 차이 — iOS 15.4+부터 지원. 인앱 웹뷰라면 OS 버전이 아니라 앱이 포함한 WebView 버전을 기준으로 판단해야 한다.
  • @supports로 fallback 감싸기 권장 — 구형 브라우저에서 선언이 무시되면서 높이가 0이 되는 사고 방지.

💡 적용 포인트

  • 기존 --vh 커스텀 프로퍼티 + window.innerHeight 리스너 조합을 CSS 한 줄로 치환 → JS 번들 감소, resize 이벤트 리스너 제거
  • 100vh 쓰는 곳을 찾아 100svh / 100dvh로 점진 교체하면 하단 CTA 가림 이슈 대부분 해소
  • iOS 15.4 미만을 지원해야 하는 서비스라면 100vh fallback을 반드시 남긴 뒤 중복 선언 또는 @supports (height: 100dvh)로 새 단위 적용 ⚠️ 실행 전 대상 브라우저 매트릭스 확인 필요

📚 참고

profile
💻 FE Developer

0개의 댓글