첫 화면을 꽉 채우려 100vh를 썼더니, 모바일 주소창이 '문의' 버튼을 반쯤 잘라먹는다 — 화면 높이를 주소창까지 계산해 담는 CSS dvh·svh 단위의 시대

첫 화면을 꽉 채우려 100vh를 썼더니, 모바일 주소창이 '문의' 버튼을 반쯤 잘라먹는다

모바일에서 첫 화면(히어로 섹션)을 화면 높이만큼 꽉 채우려고 height: 100vh를 씁니다. 그런데 정작 휴대폰에서 열어 보면 맨 아래 '문의하기' 버튼이 브라우저 주소창에 반쯤 가려 보이지 않습니다. 손님은 버튼이 있는 줄도 모르고 스크롤 없이 창을 닫습니다. 데스크톱에서는 멀쩡하던 화면이 왜 휴대폰에서만 이렇게 어긋날까요.

100vh가 모바일에서 어긋나는 진짜 이유

vh는 '화면 높이의 1%'라는 뜻입니다. 문제는 모바일 브라우저의 주소창이 스크롤에 따라 접혔다 펴졌다 한다는 데 있습니다. 오랫동안 100vh는 주소창이 접혀서 사라진 가장 큰 높이를 기준으로 계산됐습니다. 그래서 페이지를 처음 열어 주소창이 보이는 순간에는, 화면이 100vh만큼 잡혀 주소창 높이만큼 아래가 잘려 나갑니다. 첫 화면 맨 밑에 둔 버튼이 사라지는 이유가 바로 이것입니다.

예전엔 자바스크립트로 실제 높이를 쟀다

이 문제를 피하려고 개발자들은 자바스크립트로 window.innerHeight를 읽어 진짜 높이를 계산하고, 이를 CSS 변수에 넣는 꼼수를 썼습니다. 화면 크기가 바뀔 때마다 resize 이벤트로 값을 다시 계산해 갈아 끼워야 했고, 주소창이 스르륵 움직일 때마다 값이 어긋나 화면이 덜컹거리기 일쑤였습니다. 첫 화면 하나 제대로 채우자고 스크립트 한 뭉치를 매다는 셈이었습니다.

svh·lvh·dvh — 주소창을 계산에 넣는 세 가지 새 단위

이제 CSS가 주소창의 존재를 스스로 계산합니다. 뷰포트 높이를 세 가지로 나눈 새 단위가 그 답입니다.

  • svh(small): 주소창이 펼쳐진 가장 작은 화면을 기준으로 삼습니다. 100svh로 잡으면 어떤 상황에서도 버튼이 잘리지 않습니다.
  • lvh(large): 주소창이 접힌 가장 큰 화면 기준으로, 기존 100vh와 같은 동작입니다.
  • dvh(dynamic): 주소창이 접혔다 펴질 때마다 값이 실시간으로 따라 바뀝니다. 자바스크립트가 하던 일을 CSS가 그대로 대신합니다.

작은 회사 웹사이트에는 이렇게 쓴다

첫 화면과 CTA 버튼이 항상 보여야 한다면 100svh가 안전합니다. 어떤 기기, 어떤 순간에도 주소창에 가려지지 않기 때문입니다. 화면이 스크롤에 맞춰 자연스럽게 꽉 차오르는 몰입감을 주고 싶다면 100dvh를 쓰되, 값이 계속 바뀌며 화면이 조금씩 움직일 수 있다는 점만 감안하면 됩니다. 대부분의 소상공인 홈페이지라면 '버튼이 절대 잘리지 않는' svh가 실무에서 가장 무난한 선택입니다.

안전하게 적용하는 법

svh·lvh·dvh는 최신 브라우저에 모두 자리 잡은 표준입니다. 다만 아주 오래된 브라우저를 배려하려면 같은 속성을 두 줄로 겹쳐 적어 두면 됩니다. 먼저 height: 100vh를 적고 그 아래 height: 100svh를 적으면, 새 단위를 아는 브라우저는 아래 줄을, 모르는 브라우저는 위 줄을 씁니다. 문법 한 줄로 예전과 지금을 모두 감싸는 안전망입니다.

첫 화면에서 버튼 하나가 잘리는 작은 어긋남이, 손님에게는 '연락할 방법이 없는 가게'로 읽힙니다. CYAN 에이전시는 작은 회사 웹사이트를 만들 때 이런 모바일 디테일까지 기기별로 직접 확인해, 손님이 어느 화면에서 들어오든 첫 화면과 문의 버튼이 온전히 보이도록 다듬습니다.