반응형을 처음 배울 때 나는 유연한 격자와 미디어 쿼리부터 열심히 짰다. 그런데 아무리 공들여도 휴대폰에서 글씨가 여전히 작게 나오고 배치가 제멋대로였다. 원인을 한참 뒤에야 찾았는데, 문서 머리에 뷰포트 메타 태그 한 줄이 빠져 있었다. 그 한 줄이 없으면 앞서 짠 반응형 스타일 전체가 거의 무의미해진다는 걸 그때 알았고, 이후로는 이 태그를 가장 먼저 챙기게 되었다.


이번 편은 그 한 줄에 관한 이야기다. 뷰포트 메타 태그가 정확히 무엇을 지시하는지, 각 값이 어떤 역할을 하는지, 그리고 잘못 쓰면 어떤 접근성 문제가 생기는지를 내 실수와 함께 풀어본다. 반응형의 진짜 첫 단추라고 부를 만한 태그라서, 이 편을 건너뛰면 뒤의 모든 편이 흔들린다. 그만큼 작지만 결정적인 태그다.

1. 뷰포트가 없으면 벌어지는 일

뷰포트는 브라우저가 웹 페이지를 그리는 가상의 창을 뜻한다. 모바일 브라우저는 오래된 데스크톱용 사이트도 그럭저럭 보여주려고 꾀를 하나 부린다. 뷰포트 메타 태그가 없으면 화면 폭을 대략 구백팔십 픽셀쯤으로 가정하고 페이지를 그린 뒤, 그 결과를 통째로 축소해서 좁은 화면에 욱여넣는다. 넓은 책상에 펼쳐 그린 그림을 손바닥만 한 액자에 억지로 끼우는 셈이다.


이 축소가 바로 글씨가 깨알처럼 보이는 원인이다. 데스크톱 폭으로 그린 화면을 손바닥만 한 기기에 맞춰 줄이니, 사람 눈으로는 도저히 읽을 수 없는 크기가 된다. 나는 이 현상을 처음 봤을 때 내 폰트 설정이 잘못된 줄 알고 엉뚱한 곳을 한참 헤맸다. 정작 문제는 폰트가 아니라 브라우저가 인식한 화면 폭에 있었다.


더 큰 문제는 미디어 쿼리가 먹지 않는다는 점이다. 브라우저가 폭을 구백팔십 픽셀로 가정해버리니, 좁은 화면을 겨냥한 조건이 아예 발동하지 않는다. 나는 분명히 좁은 화면 규칙을 짰는데도 적용되지 않아서, 코드가 틀렸나 싶어 몇 번이고 다시 들여다봤다. 규칙은 멀쩡했고, 브라우저가 좁은 화면임을 모르고 있었을 뿐이다.


결국 반응형의 전제는 브라우저가 실제 기기 폭을 있는 그대로 인식하는 것이다. 그래야 유연한 격자도 화면에 맞게 줄고, 미디어 쿼리도 제 폭에서 발동한다. 이 전제를 만들어주는 것이 바로 뷰포트 메타 태그이고, 그래서 나는 이것을 반응형의 스위치라고 부른다. 스위치를 켜지 않으면 나머지 장치가 아무리 훌륭해도 불이 들어오지 않는다.


실제로 이 태그 한 줄을 넣기 전과 후는 하늘과 땅 차이다. 넣기 전에는 아무리 다듬어도 축소된 데스크톱 화면일 뿐이고, 넣은 뒤에야 비로소 기기 폭에 맞춘 진짜 모바일 화면이 나타난다. 나는 새 페이지를 만들 때 이 태그부터 넣는 습관이 몸에 뱄다. 한 번 크게 데인 뒤로 생긴 버릇이다.


그래서 이 태그는 있으면 좋은 것이 아니라 없으면 안 되는 것이다. 반응형을 이야기하면서 이 한 줄을 빠뜨리는 건 문을 만들지 않고 방을 꾸미는 격이다. 아무리 안을 예쁘게 꾸며도 들어갈 수 없으면 소용이 없다는 걸 나는 뒤늦게 배웠다. 이 편을 첫머리에 둔 이유도 바로 그 때문이다.

2. 표준 조합의 두 값

가장 널리 쓰는 표준 조합은 폭을 기기 폭에 맞추고 초기 배율을 일대일로 두는 것이다. 앞의 값인 width=device-width는 브라우저가 그리는 폭을 기기의 화면 폭에 맞추라는 뜻이다. 이 값 덕분에 브라우저가 구백팔십 픽셀 같은 가짜 폭을 버리고 실제 폭을 쓴다. 사실상 반응형을 여는 열쇠가 이 한 조각이다.


뒤의 값인 initial-scale=1.0은 페이지가 처음 열릴 때의 확대 배율을 일대일로 지정한다. 이 값이 없으면 기기에 따라 이상한 배율로 시작해 화면이 어긋나 보일 수 있다. 나는 두 값을 항상 짝으로 넣는데, 하나만 넣으면 특정 기기에서 예상 밖의 결과가 나오기 때문이다. 둘이 함께 있어야 비로소 조합이 완성된다.


이 두 값이 함께 서면 브라우저는 기기 폭을 그대로 인식하고, 그 폭을 기준으로 픽셀을 계산한다. 여기서 말하는 픽셀은 물리적인 점의 개수가 아니라 시아이에스에스가 다루는 논리적 픽셀이다. 고해상도 화면이라도 이 논리적 픽셀을 기준으로 그려지기 때문에 글씨 크기가 일관되게 유지된다. 화소가 촘촘해져도 글씨가 갑자기 작아지지 않는 이유가 여기에 있다.


내가 초반에 헷갈린 것이 바로 이 논리적 픽셀 개념이었다. 최신 휴대폰은 물리적으로 아주 많은 점을 가졌지만, 뷰포트가 인식하는 폭은 그보다 훨씬 작은 숫자다. 이 덕분에 같은 16px 글씨가 어떤 기기에서도 비슷한 실제 크기로 보인다는 사실을 이해하고 나서야 마음이 놓였다. 화소 수와 화면 폭을 분리해서 생각하는 순간 모든 것이 명료해졌다.


이 표준 조합은 사실상 거의 모든 사이트의 기본값이다. 특별한 이유가 없다면 이 두 값만으로 충분하고, 나머지 값은 필요할 때만 더한다. 나는 오랫동안 이 기본형만으로 대부분의 페이지를 무리 없이 만들어 왔다. 기본형이 이렇게 튼튼하니 굳이 복잡하게 갈 이유가 없었다.


중요한 건 이 태그를 문서 머리 부분의 이른 위치에 두는 것이다. 브라우저가 페이지를 그리기 시작하기 전에 이 지시를 읽어야 하기 때문이다. 늦게 두면 브라우저가 한 번 잘못 그린 뒤 다시 그리는 낭비가 생길 수 있어서, 나는 문자 인코딩 선언 바로 다음쯤에 배치한다. 머리 부분의 앞자리를 이 태그에게 내어주는 셈이다.

3. 확대를 막으면 안 되는 이유

뷰포트 태그에는 최대 배율을 제한하거나 사용자 확대를 아예 막는 값도 있다. 예전에 나는 디자인이 흐트러지는 게 싫어서 사용자 확대를 막는 값을 넣은 적이 있다. 화면을 손가락으로 확대하지 못하게 하면 내가 의도한 배치가 항상 유지되니 편하다고 생각했다. 지금 돌아보면 참으로 이기적인 판단이었다.


그런데 그것은 명백한 접근성 위반이었다. 저시력 사용자는 화면을 확대해서 글씨를 크게 키워 읽는데, 확대를 막으면 그들이 콘텐츠에 접근할 길을 아예 끊어버리는 셈이다. 웹 접근성 지침은 텍스트를 이백 퍼센트까지 확대할 수 있어야 한다고 못 박고 있다. 내 편의를 위해 누군가의 접근을 막은 것이나 다름없었다.


그래서 나는 그 뒤로 최대 배율 제한과 사용자 확대 금지 값을 절대 넣지 않는다. 내 디자인이 조금 흐트러지는 것보다, 누군가 페이지를 읽지 못하는 것이 훨씬 큰 문제이기 때문이다. 확대를 막고 싶은 유혹이 들 때마다 나는 이 원칙을 떠올린다. 원칙을 정해두니 흔들릴 일이 사라졌다.


흥미롭게도 어떤 최신 브라우저는 사용자 확대 금지 값을 아예 무시하기도 한다. 접근성을 지키기 위해 브라우저가 개발자의 나쁜 선택을 덮어쓰는 것이다. 그러니 확대를 막으려는 시도는 접근성만 해칠 뿐 실효도 없는 경우가 많다. 막으려 해도 막히지 않으니 시도할 이유가 더더욱 없다.


확대를 막지 않아도 디자인을 지킬 방법은 얼마든지 있다. 유연한 격자와 적절한 글자 크기, 넉넉한 여백을 갖추면 사용자가 굳이 확대할 필요 자체가 줄어든다. 나는 확대를 억지로 막는 대신, 확대하지 않아도 읽기 편한 페이지를 만드는 쪽으로 방향을 틀었다. 막는 것이 아니라 필요를 없애는 것이 옳은 해법이었다.


결국 뷰포트 태그는 기기 폭을 인식하는 스위치일 뿐, 사용자의 자유를 제한하는 도구가 아니다. 나는 이 태그를 다룰 때 항상 사용자가 스스로 화면을 조절할 권리를 지켜준다는 원칙을 지킨다. 이 원칙이 결국 더 많은 사람에게 열린 페이지를 만든다. 접근성은 이렇게 작은 태그의 값 하나에서도 갈린다.

4. 노치와 가상 키보드 대응

기본 조합 외에 상황에 따라 더하는 값들이 있다. 그중 하나가 화면을 물리적 끝까지 채우게 하는 값이다. 이 값을 넣으면 페이지가 노치나 둥근 모서리 뒤까지 확장되는데, 최신 휴대폰의 안전 영역을 다루려면 이 값이 전제가 된다. 화면을 끝까지 쓰겠다는 선언인 셈이다.


이 값을 넣지 않으면 안전 영역을 알려주는 시아이에스에스 함수가 모두 영을 반환한다. 즉 노치 대응을 하려면 먼저 이 뷰포트 값으로 화면을 끝까지 확장해두어야 한다. 나는 노치 대응을 다루는 편에서 이 연결을 다시 자세히 설명할 생각이다. 여기서는 둘이 짝으로 움직인다는 점만 기억하면 충분하다.


또 하나 최근 표준화된 값은 가상 키보드가 뜰 때 뷰포트가 어떻게 반응할지를 정하는 것이다. 휴대폰에서 입력칸을 누르면 화면 아래에서 키보드가 올라오는데, 이때 레이아웃이 어떻게 밀리거나 겹칠지를 개발자가 제어할 수 있다. 예전에는 이 동작을 브라우저에 맡길 수밖에 없었지만 이제는 손댈 여지가 생겼다.


이 값에는 크게 세 가지 선택지가 있다. 키보드가 시각적 영역만 줄이게 두는 기본 방식, 레이아웃 자체를 줄여 콘텐츠가 키보드 위로 다시 흐르게 하는 방식, 그리고 키보드가 콘텐츠 위에 그냥 겹치게 두는 방식이다. 상황에 맞는 것을 고르면 입력 화면의 어색함이 크게 줄어든다. 화면마다 어떤 동작이 자연스러운지가 다르기 때문이다.


나는 채팅이나 댓글처럼 입력이 잦은 화면에서 이 값을 특히 신경 쓴다. 키보드가 올라올 때 방금 입력한 칸이 키보드에 가려지면 사용자가 자기가 무엇을 쓰는지 못 보게 되어 답답하기 때문이다. 이 값을 적절히 쓰면 그 답답함을 상당히 덜 수 있다. 작은 설정 하나가 입력 경험을 통째로 바꾼다.


다만 이 확장 값들은 필요할 때만 더하는 것이 좋다. 모든 페이지에 무턱대고 넣기보다, 노치를 활용하거나 입력이 많은 화면처럼 필요가 분명한 곳에만 쓰는 편이 깔끔하다. 나는 기본형을 두고 상황에 따라 값을 하나씩 얹는 방식으로 관리한다. 기본은 단순하게, 확장은 이유가 있을 때만이 내 원칙이다.

5. 실무에서 챙기는 점검 목록

실무에서 뷰포트 태그를 다룰 때 나는 몇 가지를 습관처럼 점검한다. 가장 먼저 태그가 문서 머리에 실제로 존재하는지 확인한다. 남이 만든 템플릿을 가져다 쓸 때 이 태그가 빠져 있거나 잘못된 값이 들어 있는 경우가 의외로 많기 때문이다. 있으려니 하고 넘겼다가 낭패를 본 적이 여러 번이다.


다음으로 사용자 확대를 막는 값이 몰래 들어 있지 않은지 살핀다. 예전 코드를 복사해 쓰다 보면 접근성을 해치는 값이 딸려 오는 경우가 있다. 나는 이 값을 발견하면 이유를 따지지 않고 곧바로 제거한다. 확대를 막을 정당한 이유는 거의 없기 때문이다. 물려받은 나쁜 습관을 여기서 끊는 셈이다.


실제 기기에서 열어보는 것도 빼놓지 않는다. 개발자 도구의 모바일 모드는 편리하지만 진짜 기기와 미묘하게 다를 때가 있다. 특히 주소창이 접히고 펼쳐지는 동작이나 확대 배율은 실기기에서만 정확히 확인되므로, 나는 마지막 점검을 늘 손에 든 폰으로 한다. 화면 안의 모의 기기와 손안의 진짜 기기는 다르다.


글씨 크기가 읽을 만한지도 눈으로 확인한다. 뷰포트가 제대로 잡혀 있으면 16px 정도의 본문이 휴대폰에서도 편안하게 읽힌다. 만약 여전히 글씨가 작게 보인다면 뷰포트 태그가 없거나 값이 잘못되었을 가능성이 크다. 글씨 크기는 뷰포트 상태를 가장 빠르게 알려주는 신호다.


확대 테스트도 한다. 손가락으로 화면을 벌려서 이백 퍼센트까지 키워보고, 그때 콘텐츠가 잘리거나 옆으로 밀리지 않는지 살핀다. 확대가 부드럽게 되고 텍스트가 커지면 접근성 관점에서 합격이다. 이 간단한 확인이 나중의 민원을 미리 막아준다. 몇 초의 점검이 며칠의 수고를 아껴준다.


정리하면 뷰포트 메타 태그는 브라우저가 기기의 실제 폭을 인식하게 만드는 반응형의 첫 단추이며, 기기 폭에 맞추고 초기 배율을 일대일로 두는 조합이 표준이다. 사용자 확대는 절대 막지 말고, 노치나 가상 키보드 같은 특수 상황에만 확장 값을 더한다. 다음 편에서는 이 폭을 기준으로 배치를 언제 바꿀지 결정하는 브레이크포인트 전략을 다룬다. 폭을 인식했으니 이제 그 폭을 어떻게 나눌지가 관건이다.