Safari의 100vh 문제

Safari의 100vh 문제

100vh?

CSS의 vh 단위는 1% of Viewport Height이다. vw1% of Viewport Width이고.

나는 이 단위를 알게 된 시점부터 지금까지 꾸준히 즐겨 사용하고 있었다. 이전에는 html, bodywidth, height를 각각 100%로 지정하고, 하위 엘리먼트에서 또 적용하고 하는 식으로 페이지가 뷰포트에 꽉 차게 구현해야 했었지만1 이 단위가 나오고 나서는 간단하게 뷰포트에 꽉 채울거면 너비는 100vw로, 높이는 100vh로 지정하면 됐기 때문이다.

vw, vh가 만능은 아니다.

하지만 위 이야기는 데스크탑 버전의 웹 페이지를 작업할 때만 해당되는 말이다. 반응형 웹이랍시고 데스크탑과 모바일 모두에서 예쁘게 잘 보여야 제대로 만들어진 페이지란 소리를 듣는 요즘 세상에서는 vw, vh도 만능은 아니다.

어디까지가 Viewport인가

그 이유는 바로 모바일 브라우저들의 지랄맞은 Address Bar(또는 Navigation Bar) 때문이다. 화면 크기가 제한적인 모바일 브라우저의 특성 때문에 모바일 브라우저의 주소창 영역은 그 높이가 일정하지 않다.

크롬, 사파리, 오페라, 웨일, 파이어폭스, 키위 등 브라우저마다 높이가 다른 것은 둘째 치더라도, 하나의 브라우저에서도 주소창이 스크롤 중에 위나 아래로 쏙 들어가버리는 경우가 생기기 때문에 항상 높이가 변한다고 봐도 무방하다.

문제는, 이런 상황에서 vh 유닛을 사용할 때 발생한다.

Viewport는 Address Bar 영역도 포함한다.

이게 정말 사람을 미치게 하는 부분이다. 데스크탑용 브라우저에서 뷰포트라 하면 주소창 및 메뉴 영역을 제외한, 실제로 페이지가 렌더링되는 부분을 말한다. 즉 document가 렌더링될 수 있는 영역만을 뷰포트라고 정의하고 이를 통해 직관적으로 vw, vh를 사용할 수 있다.

그러나 모바일은 다르다. 일부 모바일 브라우저는 주소창 영역까지도 viewport라고 정의한다. 그럼 무슨 일이 생길까?

height: 100vh -> 위나 아래가 잘림

무슨 일이 생기긴. 화면을 가득 채울 걸 의도하고 height: 100vh따위를 쓰면 해당 모바일 브라우저에서 위나 아래가 잘리게 된다. 얼만큼? 해당 브라우저의 주소창 높이만큼.

예를 들어 다음과 같은 상황을 가정해보자.

SPA 웹앱을 작성한다. 화면의 맨 아래에는 Navigation 컴포넌트를 배치해 페이지를 넘길 수 있게 만든다.

그리고 이를 위해 컨테이너의 높이와 너비를 각각 100vh, 100vw로 지정하고, flexbox를 사용해 컨텐츠 렌더 영역은 flex: 1 0 0으로, 네비게이션 컴포넌트 영역은 flex: 0 0 2.5rem으로 만들었다고 가정해보자.

데스크탑 브라우저에서 보면 의도한 대로 잘 보일 것이다. 일부 모바일 브라우저에서도 잘 보인다. 한 번에 잘 만들어진 것일까? 어림도 없지.

아이폰 Safari에서 네비게이션 컴포넌트가 주소창에 가려 보이지 않을 것이다. 물론 비슷하게 작동하는 다른 브라우저도 마찬가지다. 심지어 아이폰 크롬도 마찬가지이다. 안드로이드의 크롬은 문제가 없었지만 아이폰 크롬에서는 문제가 발생하는 것을 보고 얼이 빠졌던 기억이 아직도 생생하다.2

해결 방법은?

1. 옛날로 돌아가자. height: 100% 사용 (비추천)

첫 번째 해결 방법은 다시 옛날로 돌아가 html, bodyheight: 100%를 지정하고, 최종적으로 사용될 엘리먼트의 컨테이너까지 드릴로 뚫듯 height: 100%를 지정하며 내려와서 이를 사용하는 것이다.

당연히 추천할만한 방법은 못 된다. 그 어떤 라이브러리도 사용하지 않고 모든 걸 직접 만들어서 쓰겠다면 말리진 않겠으나, 그렇다고 하더라도 어느 순간에는 문제가 발생할 것이다. 예를 들어 엘리먼트의 위치 및 바운더리를 계산해야 하는 상황에서 예기치 않은 문제가 발생한다던가.

2. 지금이 어느 시대인데. dvh 단위를 사용하자.

앞서 설명했듯 이 문제는 IOS에서 두드러지게 나타나는 문제이다. IOS 이용자가 한두 명이면 그냥 무시해버리고 ‘니들이 고쳐~’ 하면 될 일이지만 안타깝게도 나를 포함해 IOS 사용자가 한둘이 아니라서 결국 CSS에 dvh라는 단위가 추가되기에 이른다.

1dvh1% of Dynamic Viewport Height이다. vw와 달리 dvw는 존재하지 않는다. 애초에 이런 상황 때문에 나온 단위이기 때문에 당연하긴 하지만.

그렇다면 Dynamic Viewport Height란 무엇인가? 이름에서 직관적으로 보이듯 동적으로 변하는 뷰포트 높이를 말한다. 즉 **Address Bar 영역이 슬라이드될 때, 나타날 때, 사라질 때마다 변하는 동적인 뷰포트 높이의 1%**가 1dvh인 것이다.

이를 사용하면 위와 같은 어이없는 상황을 유연하게 대처할 수 있다. 당연히 공식 스펙에서 지원되는 단위이므로 calc 메서드 등에도 정상적으로 사용할 수 있다.

dvh 브라우저 지원

관련 문서를 보면 모든 모던 브라우저에서 완전히 지원되는 기능이므로 안심하고 사용하면 되겠다.


  1. 특수한 경우에는 Javascript까지 동원했어야 했다. ↩︎

  2. 크로미움 프로젝트를 보면 IOS용 크롬은 여전히 웹킷을 사용한다. 아마 이 때문에 발생한 차이가 아닌가 싶다. ↩︎

댓글

이 블로그의 인기 게시물

C# 남아도는 메모리에도 불구하고 OutOfMemoryException이 발생한다면?

MySQL 데이터 타입과 Java 데이터 타입 비교/매칭

테일즈위버 OST 전곡 모음