반응형
책방 E의 새 행사 일정 페이지는 휴대폰에서도, 회사 모니터에서도 멀쩡했다. 그런데 지후가 브라우저 창의 오른쪽 끝을 잡고 천천히 줄이자, 폭이 700픽셀을 조금 넘는 곳에서 행사 카드가 화면 끝까지 늘어나 한 줄이 마흔 자를 넘겼고, "신청하기" 버튼은 손바닥보다 길어졌다. 768픽셀이 되는 순간 화면이 갑자기 다른 모습으로 바뀌었다. 세 폭(360·768·1280)으로 그린 시안 어디에도 700픽셀은 없었다. 반응형 디자인은 그 몇 개의 폭이 아니라 그 사이의 모든 폭을 설계하는 일이다.
- 고정폭 레이아웃과 유동 레이아웃, 최대 폭을 둔 유동 레이아웃이 화면 폭에 따라 어떻게 달라지는지 설명한다.
- 중단점을 기기 이름이 아니라 콘텐츠가 깨지는 곳에 두고, 그것을
em으로 적는 이유를 안다. - 모바일 우선(
min-width) 방식으로 화면을 쌓아 올리는 순서를 이해한다. clamp()로 제목 크기와 간격을 화면 폭에 따라 매끄럽게 바꾸고, 글줄 길이에 상한을 둔다.- 컨테이너 쿼리와
srcset·sizes로, 부품과 이미지가 놓인 자리에 맞게 바뀌게 한다.
고정, 유동, 그리고 그 사이
책방 E의 지금 웹사이트는 2019년쯤 만든 고정폭 레이아웃(Fixed-width layout)이다. 페이지 전체의 폭을 960픽셀로 못 박은 디자인이다. 2000년대 후반부터 한동안 웹 디자인의 표준처럼 쓰였다. 당시 흔한 모니터 해상도가 1024×768이었고, 960은 2·3·4·5·6·8·10·12로 나누어떨어져 단을 나누기 좋았다. 화면이 960보다 넓으면 양옆이 비고, 좁으면 넘친다. 종이 포스터처럼 크기를 먼저 정하고 그 안에 그리는 방식이다.
휴대폰이 나오자 고정폭 페이지는 두 가지 방식으로 망가졌다. 2장에서 본 대로, 뷰포트를 알려 주는 메타 태그가 없는 페이지를 휴대폰 브라우저는 폭 980픽셀 안팎의 가상 화면에 그린 뒤 통째로 줄여 보여 준다. 글자가 깨알처럼 작아진다. 메타 태그를 넣으면 이번에는 360픽셀 화면에 960픽셀 페이지가 들어가 가로로 넘친다. 독자는 한 줄을 읽을 때마다 화면을 좌우로 밀어야 한다.
반대쪽 끝은 유동 레이아웃(Fluid layout)이다. 폭을 픽셀이 아니라 화면 폭의 비율(%)이나 fr로 적어, 화면이 넓어지면 함께 넓어지고 좁아지면 함께 좁아진다. 넘치지는 않지만 끝까지 밀면 다른 문제가 생긴다. 좁은 화면에서는 옆 칸까지 같은 비율로 줄어 글 칸이 손가락 폭만 해지고, 넓은 모니터에서는 한 줄이 백 자를 넘는다. 그래서 실무에서는 유동 레이아웃에 최대 폭(max-width)을 함께 둔다. 4장에서 정한 1,200픽셀이 그 값이다. 그보다 넓은 화면에서는 내용이 가운데에 멈추고 양옆 여백만 늘어난다.
아래는 책방 E 행사 일정 페이지의 가상 화면이다. 맨 위 눈금자를 끌어 화면 폭을 320에서 1,600픽셀까지 바꾸고, 세 전략을 번갈아 본다. 폭이 넓을 때는 가상 화면을 줄여서 그린다. "viewport 메타 태그 없이"를 켜면 메타 태그가 없던 시절의 휴대폰 화면이 된다.
고정폭·유동·최대 폭
세 전략 가운데 어느 것도 360픽셀과 1,600픽셀에서 동시에 좋지는 않았다. 고정폭은 한 폭만 책임지고, 유동은 모든 폭을 같은 모양으로 늘인다. 필요한 것은 폭에 따라 모양 자체를 바꾸는 장치다. 웹 디자이너 이선 마콧(Ethan Marcotte)은 2010년 A List Apart에 실은 글 「Responsive Web Design」에서 유동 그리드, 유연한 이미지, 미디어 쿼리 세 가지를 묶어 반응형 웹 디자인(Responsive web design)이라고 불렀다. 화면 폭에 반응해 배치가 바뀌는 페이지라는 뜻이다. 이 장은 그 세 재료가 지금 어떻게 쓰이는지, 그리고 그 뒤에 더해진 재료(clamp(), 컨테이너 쿼리, srcset)를 차례로 본다.
user-scalable=no나 maximum-scale=1을 넣는 일이 있다. 손가락 두 개로 화면을 키우는 확대를 막는 설정이다. 글자를 키워야 읽을 수 있는 사람에게 이 설정은 페이지를 닫으라는 말과 같다. 웹 콘텐츠 접근성 지침 WCAG 2.2의 성공 기준 1.4.4(글자 크기 조정)는 글자를 200%까지 키워도 내용과 기능을 잃지 않을 것을 요구한다. 메타 태그는 width=device-width, initial-scale=1까지만 쓴다.
중단점은 콘텐츠가 정한다
폭에 따라 모양을 바꾸는 지점을 중단점(Breakpoint)이라고 한다. 중단점은 CSS의 미디어 쿼리(Media query)로 적는다. "화면 폭이 얼마 이상이면 이 규칙을 쓴다"는 조건문이다.
/* 기본: 행사 카드를 한 줄에 하나씩 쌓는다 */
.events { display: grid; gap: 1rem; }
/* 화면 폭이 35em 이상이면 날짜·글·버튼을 한 행으로 */
@media (min-width: 35em) {
.event { grid-template-columns: 8em 1fr 9.5em; }
}
중단점을 어디에 둘까. 오랫동안 쓰인 답은 기기 이름이었다. 아이폰의 320, 아이패드 세로의 768, 아이패드 가로의 1024. 지금도 많은 템플릿과 디자인 도구가 "모바일·태블릿·데스크톱" 세 칸에 이 숫자를 넣어 둔다. 문제는 2장에서 본 대로 실제 화면 폭이 그 몇 개의 숫자에 모여 있지 않다는 것이다. 휴대폰만 해도 폭이 제각각이고, 태블릿을 가로로 돌리고 노트북 창을 반으로 나누고 글자 크기를 키우면 그 사이의 모든 폭이 나온다. 기기 이름의 중단점은 그 기기들의 폭에서만 맞고, 사이에서는 운에 맡긴다.
그래서 지금 널리 쓰는 요령은 순서를 뒤집는 것이다. 가장 좁은 화면에서 시작해 창을 천천히 넓혀 가다가, 콘텐츠가 어색해지는 곳에 중단점을 둔다. 기준은 기기가 아니라 내용이다. 글줄이 너무 길어지는가, 글 칸이 너무 좁아져 제목이 세 줄로 꺾이는가, 버튼이 쓸데없이 길어지는가. 그런 곳이 콘텐츠가 "모양을 바꿔 달라"고 말하는 폭이다.
아래 시뮬레이터에서 행사 일정 페이지는 세 가지 모양을 가진다. 좁을 때는 카드를 한 줄에 하나씩 쌓고(1단), 넓어지면 날짜·글·버튼을 한 행에 놓고(행), 더 넓어지면 옆에 이달의 달력 칸을 붙인다(행 + 옆 칸). 눈금자 아래의 띠는 320~1,600픽셀의 모든 폭에서 그 폭의 모양이 깨지는지(붉은색) 괜찮은지(초록색)를 미리 계산해 칠한 것이다. "직접 끌기"를 고르면 눈금자의 삼각형 중단점 두 개를 끌어 옮길 수 있다.
깨지는 곳을 찾아 중단점 두기
기기 이름의 중단점은 틀린 숫자라서가 아니라 질문이 틀려서 깨진다. "어떤 기기가 있나"를 물으면 768이 나오지만, "이 카드는 몇 픽셀부터 한 행에 들어가나"를 물으면 이 모형에서는 560 안팎이 나온다. 그리고 그 답은 카드에 무엇이 들어 있는지에 달려 있다. 날짜 칸을 넓히거나 버튼 문구를 바꾸면 중단점도 움직인다. 중단점은 레이아웃의 설정값이 아니라 콘텐츠의 성질이다.
중단점을 em으로 적은 까닭도 여기서 나온다. 미디어 쿼리 안의 em은 부모 요소가 아니라 브라우저의 기본 글자 크기(대개 16px)를 기준으로 한다(Media Queries Level 4). 사용자가 기본 글자 크기를 키우면 35em은 560픽셀에서 840픽셀로 따라 커진다. 글자가 커지면 같은 카드가 한 행에 들어가는 데 더 넓은 폭이 필요하니, 중단점이 함께 움직이는 쪽이 맞다. 픽셀로 적은 768은 그대로 남아, 글자를 키운 사람에게만 깨진 화면을 보여 준다. 다만 휴대폰 운영체제의 글자 크기 설정이 웹 페이지에 어떻게 전해지는지는 운영체제와 브라우저마다 다르므로 실제 기기에서 따로 확인한다.
mobile, tablet, desktop 같은 이름을 붙이면 머지않아 "태블릿인데 왜 모바일 레이아웃이냐"는 질문을 받는다. 폴더형 휴대폰을 펼치면 태블릿만 해지고, 노트북 창을 반으로 나누면 태블릿보다 좁아진다. 이름은 bp-1, bp-2나 narrow, wide처럼 순서와 성질만 말하게 짓고, 문서에는 "그 폭에서 무엇이 바뀌는지(카드가 한 행이 된다)"를 적는다. 그래야 콘텐츠가 바뀌어 중단점을 옮길 때 이름이 거짓말이 되지 않는다.
모바일 우선: 작은 화면부터 쌓기
미디어 쿼리는 두 방향으로 쓸 수 있다. 넓은 화면의 레이아웃을 기본으로 두고 max-width로 좁은 화면에서 하나씩 덮어쓰는 방식과, 좁은 화면의 레이아웃을 기본으로 두고 min-width로 넓은 화면에서 하나씩 더하는 방식이다. 뒤의 방식을 모바일 우선(Mobile first)이라고 부른다. 디자이너 루크 로블르스키(Luke Wroblewski)가 2011년 책 『Mobile First』에서 이름 붙여 널리 알렸다. 그가 강조한 것은 CSS의 순서보다 생각의 순서였다. 작은 화면에서 먼저 설계하면 무엇이 정말 필요한지부터 정하게 된다는 것이다.
min-width 규칙이 넓은 쪽에 한 겹씩 더해진다. 아래는 넓은 화면을 기본으로 두고 max-width로 좁은 쪽을 덮어쓰는 방식이다. 결과는 같아도, 아래 방식에서는 휴대폰이 넓은 화면의 규칙을 다 읽은 뒤 그것을 하나씩 지워야 한다.모바일 우선이 CSS에서 유리한 까닭은 단순하다. 1단 쌓기는 블록 요소의 기본 동작이라 거의 아무것도 적지 않아도 된다. 넓은 화면의 복잡한 규칙(단 나누기, 옆 칸, 행 배치)은 그것이 필요한 폭에서만 더한다. 반대로 넓은 화면을 기본으로 두면 좁은 화면에서 그 규칙을 하나하나 되돌려야 하고, 되돌리는 것을 잊은 규칙이 휴대폰에 남는다. 그리고 지금 대부분의 방문은 휴대폰에서 온다. 2장에서 본 책방 E의 방문 기록(가상)도 그랬다. 가장 많은 손님이 보는 화면을 "덮어쓴 결과"가 아니라 "기본"으로 두는 편이 안전하다.
모바일 우선은 "휴대폰 화면만 먼저 예쁘게 그린다"는 뜻이 아니다. 시안 순서로는 오히려 내용의 순위표부터다. CompositionBook 12장에서 서윤이 웹 첫 화면을 짤 때 그랬듯, 무엇이 먼저 읽혀야 하는지를 정한 순서가 1단에서는 그대로 위에서 아래로의 순서가 된다. 넓은 화면은 그 순서를 옆으로 펼치는 일이다. 순서가 정해져 있으면 넓은 화면에서 옆 칸으로 빠지는 것(이달의 달력)과 본문에 남는 것(행사 목록)도 쉽게 갈린다.
clamp(): 계단 대신 비탈
중단점은 모양을 바꾸는 장치다. 그런데 모든 것이 모양을 바꿔야 하는 것은 아니다. 제목 크기, 구역 사이의 간격처럼 "조금 더 크게, 조금 더 넓게"만 바뀌면 되는 값도 있다. 이런 값을 중단점마다 하나씩 정하면 계단이 된다. 559픽셀에서 30픽셀이던 제목이 560픽셀에서 갑자기 35픽셀로 뛴다. 창을 끄는 사람만 보는 어색함이지만, 계단이 많을수록 사이의 폭에서 비례가 어긋나는 곳도 많아진다.
CSS의 clamp(최솟값, 선호값, 최댓값)은 이 계단을 비탈로 바꾼다. 선호값을 화면 폭에 비례하는 식으로 적고, 그 값이 최솟값과 최댓값 사이를 벗어나지 않게 묶는다. 좁은 화면 폭 \(W_1\)에서 \(s_1\), 넓은 화면 폭 \(W_2\)에서 \(s_2\)가 되게 하려면 두 점을 잇는 직선을 쓴다.
TypeBook 11장에서 서윤은 이 식으로 본문 크기(17 → 18픽셀)를 이었다. 본문은 폭이 1픽셀밖에 변하지 않는 얌전한 경우다. 제목과 간격은 폭이 훨씬 크다. 아래 그래프의 두 손잡이를 끌어 \((W_1, s_1)\)과 \((W_2, s_2)\)를 바꾸면 그 식이 CSS로 적힌다. 그래프 위에서 마우스를 움직이면(휴대폰에서는 누르면) 그 폭에서의 크기로 "행사 일정"을 그려 보인다.
clamp()로 잇는 제목 크기와 간격
제목 크기의 비탈에는 지켜야 할 선이 있다. 선호값을 vw만으로 적으면(font-size: 4vw) 브라우저 확대가 듣지 않는다. 확대하면 CSS 픽셀로 잰 화면 폭이 줄어 vw 값도 함께 줄기 때문이다. 고정 부분을 rem으로 섞고, 최댓값을 최솟값의 2.5배 안쪽으로 두면 200% 확대에서도 글자가 충분히 커진다(TypeBook 11장). 간격은 글자보다 너그럽다. 다만 간격이 화면 폭만 따라 커지고 글자 크기를 따르지 않으면, 글자를 키운 사람의 화면에서는 글자에 비해 간격이 좁아진다. 간격의 비탈도 rem을 섞어 적는다.
1vw는 뷰포트 폭의 1%다. 휴대폰 브라우저에서는 주소창이 나타났다 사라지면 뷰포트의 높이가 바뀌므로, 높이 단위 vh는 스크롤할 때 값이 흔들린다. 그래서 CSS에는 주소창이 가장 클 때 기준인 svh, 가장 작을 때 기준인 lvh, 지금 기준인 dvh가 더해졌다(CSS Values and Units Level 4). 폭 단위 vw도 데스크톱에서는 세로 스크롤 막대의 폭까지 포함해 재므로, 100vw로 폭을 정한 요소는 스크롤 막대만큼 넘쳐 가로 스크롤을 만든다. 화면 폭에 맞추려면 100%를, 글자와 간격의 비탈에는 vw를 쓰는 식으로 나누어 쓴다.
글줄 길이를 지키는 상한
유동 레이아웃이 넓은 화면에서 가장 먼저 망가뜨리는 것은 글줄 길이다. TypeBook 6장에서 본 것처럼 한 줄이 너무 길면 눈이 다음 줄의 시작으로 돌아가다 길을 잃는다. 웹 콘텐츠 접근성 지침의 성공 기준 1.4.8(시각적 표현, AAA 등급)은 글 덩어리의 폭을 한 줄 80자, 한중일 문자는 40자 이하로 둘 수 있게 하라고 적는다. 서윤은 지난여름 서점 소식 글의 최대 글줄 폭을 28em, 한 줄 37자 안팎으로 정했다.
이 상한을 무엇으로 적느냐가 반응형에서 중요하다. 픽셀로 max-width: 504px라고 적으면 기본 글자 크기에서는 28em과 같다. 그런데 글자를 키운 사람에게는 504픽셀이 그대로라 한 줄 글자 수가 줄어든다. 글자가 두 배가 되면 한 줄이 열여덟 자로 꺾인다. max-width: 28em으로 적으면 글자와 함께 폭도 커져 한 줄 글자 수가 그대로 남는다. 물론 화면 폭이 그보다 좁으면 화면 폭이 먼저 상한이 된다.
글줄 길이 상한: px로, em으로
상한은 글 덩어리에만 둔다. 페이지 전체를 28em으로 묶으면 넓은 화면에서 사진과 표, 달력까지 좁은 기둥에 갇힌다. 반응형 페이지에는 보통 폭의 층이 셋 있다. 화면 폭, 콘텐츠의 최대 폭(책방 E에서는 1,200픽셀), 그리고 글 덩어리의 최대 글줄 폭(28em). 사진과 그리드는 둘째 층까지, 글은 셋째 층까지 늘어난다. 이 셋을 구분해 두면 "넓은 화면을 어떻게 채울까"라는 질문이 "무엇을 넓게, 무엇을 좁게 둘까"로 바뀐다.
컨테이너 쿼리: 놓인 자리를 보고 바뀐다
미디어 쿼리는 화면 전체의 폭만 본다. 그런데 웹 페이지의 부품은 화면 폭이 아니라 자기가 놓인 칸의 폭 안에서 산다. 같은 "신간 카드"가 넓은 본문 칸에도, 좁은 옆 칸에도 들어간다. 넓은 화면에서 카드를 가로형(표지 왼쪽, 글 오른쪽)으로 바꾸는 규칙을 미디어 쿼리로 적으면, 넓은 화면의 좁은 옆 칸에 들어간 카드도 가로형이 되어 글 칸이 손가락 하나만 해진다.
컨테이너 쿼리(Container query)는 질문의 대상을 화면에서 부품을 담은 칸으로 바꾼다. 칸에 container-type: inline-size를 적어 두면, 그 안의 부품은 @container (min-width: 25em)처럼 "나를 담은 칸이 25em 이상이면"이라는 조건을 쓸 수 있다. CSS Containment Module Level 3에 정의되어 있고, 2023년 초부터 주요 브라우저가 모두 지원한다.
.book-slot { container-type: inline-size; }
/* 기본은 세로형: 표지 위, 글 아래 */
.book-card { display: grid; gap: 0.75rem; }
/* 담은 칸이 25em 이상이면 가로형 */
@container (min-width: 25em) {
.book-card { grid-template-columns: 9em 1fr; }
}
아래 시뮬레이터에는 신간 카드가 두 자리에 놓여 있다. 본문 칸의 "이달의 신간"과, 넓은 화면에서는 오른쪽 옆 칸에 붙고 좁은 화면에서는 본문 아래로 내려오는 "주인의 추천"이다. 미디어 쿼리 판은 "화면 폭 56em 이상이면 가로형", 컨테이너 쿼리 판은 "담은 칸이 25em 이상이면 가로형"이다.
같은 카드, 다른 자리
컨테이너 쿼리가 생기면서 반응형의 일이 둘로 나뉘었다. 페이지 전체의 뼈대(몇 단인가, 옆 칸이 있는가)는 여전히 미디어 쿼리가 화면 폭을 보고 정한다. 부품의 모양(카드가 가로형인가 세로형인가)은 부품이 스스로 자기 칸을 보고 정한다. 부품을 만드는 사람은 "이 카드가 어느 페이지 어느 칸에 들어갈지" 몰라도 되고, 페이지를 짜는 사람은 "이 칸에 들어갈 카드가 어떤 규칙을 가졌는지" 몰라도 된다. 7장에서 다룰 컴포넌트가 이 성질 덕분에 어디에나 옮겨 놓을 수 있게 된다.
반응형 이미지: srcset과 sizes
이미지에도 폭의 문제가 있다. 서윤이 ImageBook 10장에서 정한 웹용 사진은 가로 1,600픽셀이다. 넓은 화면의 큰 사진 자리에는 맞지만, 휴대폰의 작은 썸네일 칸에 1,600픽셀 파일을 보내면 받은 픽셀 대부분을 버린다. 반대로 작은 파일 하나만 보내면 큰 화면과 고해상도 화면에서 흐릿하다. 마콧이 말한 "유연한 이미지"의 첫 단계는 max-width: 100%로 이미지를 칸보다 커지지 않게 하는 것이었다. 지금은 여기에 더해 칸에 맞는 크기의 파일을 고르게 한다.
<img src="reading-1600.webp"
srcset="reading-480.webp 480w, reading-800.webp 800w,
reading-1200.webp 1200w, reading-1600.webp 1600w"
sizes="(min-width: 56em) 384px,
(min-width: 35em) calc(50vw - 28px),
calc(100vw - 32px)"
width="1600" height="1067" alt="…">
srcset은 같은 사진을 크기별로 내보낸 파일 목록이고, 뒤의 480w는 그 파일의 가로 픽셀 수다. sizes는 "이 사진이 화면에서 차지할 폭"을 미디어 조건별로 알려 준다. 위의 예는 넓은 화면에서 사진이 세 칸 그리드의 한 칸(384픽셀), 중간 폭에서 두 칸 중 하나, 좁은 화면에서 화면 폭에서 양옆 여백을 뺀 폭이라는 뜻이다. 브라우저는 페이지의 CSS를 다 읽기 전에 이미지를 받기 시작하므로, 사진이 얼마나 크게 놓일지를 이렇게 미리 귀띔해 주어야 한다.
sizes에서 지금 화면 폭에 맞는 조건을 찾아 사진이 놓일 폭(CSS 픽셀)을 얻고, 거기에 기기 픽셀 비율(DPR)을 곱해 필요한 실제 픽셀 수를 낸 뒤, 목록에서 그 이상인 파일 하나를 고른다. 마지막 단계의 정확한 방식은 명세가 브라우저에 맡겨 두어서, 이미 받아 둔 큰 파일이 있거나 통신이 느리면 다른 파일을 고를 수도 있다.아래 시뮬레이터는 행사 사진 아홉 장이 들어가는 사진첩 페이지다. 화면 폭과 기기 픽셀 비율을 바꾸며 세 가지 적기 방식을 비교한다. sizes를 빠뜨리면 브라우저는 사진이 화면 폭 전체(100vw)를 차지한다고 가정한다.
srcset·sizes: 어느 파일이 내려오나
사진의 내용을 화면에 따라 바꾸고 싶을 때도 있다. 넓은 화면에서는 서점 전경을, 휴대폰에서는 같은 사진의 가운데 낭독자만 잘라 보이고 싶다면 <picture> 요소에 <source media="…">를 여러 개 두어 화면 조건마다 다른 사진을 지정한다. 이것을 아트 디렉션(Art direction)이라고 부른다. 같은 사진의 크기만 고르는 srcset과 달리, 어떻게 자를지를 디자이너가 정하는 일이다. 어느 경우든 width와 height 속성으로 사진의 비율을 알려 두어야 사진이 도착하기 전에 자리가 잡혀 글이 밀리지 않는다. 이 이야기는 12장에서 이어진다.
행사 일정 페이지 반응형 작업대
이 장의 재료를 한 페이지에 모은다. 행사 일정 페이지의 "첫 시안"은 기기 이름 중단점(768·1024px), 픽셀로 박은 40픽셀 제목, 상한 없는 소개 글, 언제나 펼친 메뉴를 썼다. "서윤의 선택"은 콘텐츠 중단점(35em·56em), clamp()로 잇는 제목, 28em 소개 글, 좁은 화면에서 접히는 메뉴를 쓴다. 눈금자를 끌어 폭을 바꾸고, 도경처럼 글자 크기를 키워 본다.
행사 일정 페이지: 첫 시안과 서윤의 선택
clamp(1.875rem, 1.630rem + 1.087vw, 2.5rem). 메뉴는 메뉴 항목 너비의 합이 머리 띠에 들어가지 않으면 깨짐으로 친다.)작업대에서 서윤의 선택도 모든 조합에서 완벽하지는 않다. 글자를 200%로 키우고 폭을 아주 좁히면 행사 제목 한 줄에 몇 글자 들어가지 않는다. 반응형 디자인의 목표는 깨짐이 없는 상태가 아니라, 깨질 때 덜 아프게 깨지는 상태다. 가로로 넘치는 대신 아래로 길어지고, 겹치는 대신 줄을 바꾸고, 사라지는 대신 접힌다. WCAG 2.2의 성공 기준 1.4.10(리플로)이 요구하는 것도 같은 방향이다. 폭 320 CSS 픽셀(데스크톱에서 1,280픽셀 화면을 400%로 확대한 것과 같다)에서 세로 스크롤만으로 내용을 다 읽을 수 있어야 한다.
서윤의 웹 개편 노트
700픽셀에서 늘어난 카드
1월 말, 지후가 행사 일정 페이지의 첫 코드를 올렸다. 서윤의 세 폭 시안(360·768·1280)을 그대로 옮기고, 중단점은 디자인 도구의 기본 프리셋대로 768과 1024픽셀에 두었다. 세 폭에서는 시안과 똑같았다. 회의실에서 지후가 노트북의 브라우저 창 오른쪽 끝을 잡고 천천히 줄였다. 1,024 아래로 내려오자 행 모양 카드의 설명이 다시 한 줄 40자를 넘기더니, 768 바로 위에서는 1단으로 쌓인 카드가 화면 끝까지 늘어나 설명 한 줄이 마흔 자를 훌쩍 넘었다. 버튼은 손바닥보다 길었다. "시안에는 700이 없잖아요. 그런데 접는 휴대폰을 펼치면 딱 이쯤이에요."
서윤은 이 장의 방식대로 가장 좁은 폭에서 출발해 창을 넓혀 가며 콘텐츠가 어색해지는 곳을 적었다. 이 장의 모형으로 계산하면, 1단 카드는 화면 폭 580픽셀을 넘으면 설명이 40자를 넘고, 행 모양은 549픽셀부터 글 칸이 12자를 넘어 들어간다. 첫 중단점은 그 사이, 35em(560픽셀)으로 정했다. 행 모양은 910픽셀을 넘으면 다시 설명이 길어지고, 옆에 달력 칸을 붙인 모양은 853픽셀부터 가능하다. 둘째 중단점은 56em(896픽셀)이다. 둘 다 em으로 적었다. 한도경이 글자 크기를 가장 크게 해 둔 휴대폰과, 글자 크기를 150%로 맞춘 서윤의 노트북 브라우저로 확인해 보니 기기 이름 중단점에서는 768 바로 위와 1,024 위쪽에 새로 깨지는 구간이 생겼고, em 중단점은 840·1,344픽셀로 함께 밀려 깨지지 않았다. 도경은 "글자를 키우면 화면이 아예 다른 모양이 되는 게 오히려 편하네. 옛날 사이트는 그냥 다 겹쳤거든" 했다.
제목 크기는 중단점마다 정하던 30·35·40픽셀의 계단을 버리고, 화면 폭 360~1,280픽셀 사이를 잇는 비탈로 바꿨다. 기울기는 10px ÷ 920px = 1.087vw, 고정 부분은 30 − 360 × 10/920 ≈ 26.09px = 1.630rem이다. 최댓값이 최솟값의 1.33배라 확대에도 안전하다. 행사 설명과 서점 소개 같은 글 덩어리는 TypeBook 여름 노트의 28em 상한을 그대로 가져왔다. 상한을 504px이 아니라 28em으로 적은 까닭을, 서윤은 도경의 휴대폰 화면을 캡처해 노트에 붙였다. 신간 카드는 본문과 옆 칸 두 곳에 들어가므로 화면 폭이 아니라 담은 칸의 폭(25em)으로 가로형과 세로형을 가르기로 했다. 지후는 "이제 시안에 숫자 대신 규칙이 적혀 있어서 좋네요" 했다.
35em (560px)
중단점 256em (896px)
페이지 제목30 → 40px
글줄 상한28em
35em(기본 글자 크기에서 560px, 1단 → 행)과 56em(896px, 행 → 행 + 옆 칸). 모바일 우선(min-width)으로 적고 이름은 기기가 아니라 순서로 짓는다. 페이지 제목: 화면 폭 360~1,280px에서 30 → 40px, clamp(1.875rem, 1.630rem + 1.087vw, 2.5rem). 본문 글 덩어리의 최대 글줄 폭 28em(약 37자, TypeBook 6장 값). 콘텐츠 최대 폭은 4장의 1,200px, 화면 가장자리 여백은 3장의 16px. 신간 카드는 컨테이너 쿼리로, 담은 칸이 25em 이상이면 가로형.핵심 정리
- 고정폭 레이아웃은 한 폭만 책임지고, 유동 레이아웃은 모든 폭을 같은 모양으로 늘인다. 유동에 최대 폭을 더하면 넓은 화면 문제가, 중단점을 더하면 좁은 화면 문제가 풀린다.
- 중단점은 기기 이름(768, 1024)이 아니라 콘텐츠가 어색해지는 곳에 둔다. 가장 좁은 폭에서 시작해 창을 넓히며 글줄이 길어지거나 칸이 좁아지는 곳을 찾는다.
- 미디어 쿼리의 em은 브라우저 기본 글자 크기를 기준으로 하므로, em으로 적은 중단점은 사용자가 글자를 키우면 함께 밀린다. px 중단점은 그대로 남아 글자를 키운 사람에게 깨진 화면을 보인다.
- 모바일 우선은 1단을 기본으로 두고
min-width로 넓은 화면의 규칙을 더하는 방식이다. 내용의 순위표가 1단의 순서가 된다. - 모양은 그대로 두고 크기만 바뀌어야 하는 값(제목, 간격)은
clamp(최솟값, rem + vw, 최댓값)로 계단 대신 비탈을 만든다. vw만 쓰면 확대가 듣지 않는다. - 글 덩어리에는 em으로 적은 최대 글줄 폭(예: 28em)을 둔다. 화면 폭, 콘텐츠 최대 폭, 글줄 폭의 세 층을 나눈다(WCAG 1.4.8: 한중일 문자 40자).
- 컨테이너 쿼리는 부품이 놓인 칸의 폭을 보고 모양을 바꾼다.
srcset·sizes는 사진이 놓일 폭과 DPR에 맞는 파일을 고르게 한다.sizes를 빠뜨리면 브라우저는 화면 폭 전체를 가정한다.
확인 퀴즈
1. 1단으로 쌓은 행사 카드는 화면 폭 610픽셀부터 설명이 한 줄 40자를 넘고, 날짜를 옆으로 뺀 행 모양은 540픽셀부터 들어간다. 중단점을 두기에 가장 알맞은 곳은?
2. 페이지 제목을 clamp()로 화면 폭 360픽셀에서 30픽셀, 1,280픽셀에서 40픽셀이 되게 이었다. 화면 폭 820픽셀에서 제목 크기는?
3. 넓은 화면에서만 가로형이 되도록 신간 카드를 @media (min-width: 56em)으로 바꿨더니, 넓은 화면의 좁은 옆 칸에 들어간 같은 카드의 글 칸이 쪼그라들었다. 가장 알맞은 처방은?
4. 사진의 칸 폭이 400 CSS 픽셀이고 기기 픽셀 비율이 2인 휴대폰에서, srcset="a.webp 480w, b.webp 800w, c.webp 1200w"와 알맞은 sizes를 적었다. 브라우저가 고를 가능성이 가장 큰 파일은?
sizes로 칸 폭(400 CSS 픽셀)을 알고, 여기에 DPR 2를 곱해 실제 픽셀 800이 필요하다고 계산한다. 그 이상인 파일 중 가장 작은 800w가 맞다. 480w는 흐리게 보이고, 1,200w는 필요보다 2.25배 많은 픽셀을 받는다. 명세는 마지막 고르기를 브라우저에 맡기므로 캐시나 통신 상태에 따라 달라질 수는 있지만, 여러 파일을 다 받지는 않는다.출처
- Ethan Marcotte, "Responsive Web Design", A List Apart, 2010 — 유동 그리드·유연한 이미지·미디어 쿼리의 조합(요약).
- Luke Wroblewski, Mobile First, A Book Apart, 2011(요약).
- W3C, Media Queries Level 4 — 미디어 쿼리 안의 상대 단위(em)는 초깃값(사용자 기본 글자 크기)을 기준으로 한다.
- W3C, CSS Values and Units Module Level 4 —
clamp(), vw와 작은·큰·동적 뷰포트 단위(svh·lvh·dvh). - W3C, CSS Containment Module Level 3 —
container-type과@container. - WHATWG, HTML Living Standard —
img의srcset(w 서술자)·sizes,picture와source. 후보 중 무엇을 고를지는 사용자 에이전트에 맡긴다. - W3C, Web Content Accessibility Guidelines (WCAG) 2.2, 성공 기준 1.4.4 Resize Text(AA), 1.4.8 Visual Presentation(AAA), 1.4.10 Reflow(AA).
- 시뮬레이터의 레이아웃 판정 기준(한 줄 40자, 글 칸 12자)과 화면 폭 모형, 사진 용량은 이 책이 정한 교육용 가상 값이다.