한글 본문을 좁은 칸에 넣으면 어절 한가운데서 줄이 바뀌는 일이 생깁니다. “최적화” 가 “최” 와 “적화” 로 갈리는 식입니다. 문법적으로는 아무 문제가 없지만, 읽는 사람은 한 덩어리로 인식하던 말이 쪼개지는 순간 흐름을 놓칩니다.
브라우저가 한글을 끊는 방식
기본값 word-break: normal에서 브라우저는 한중일 문자(CJK) 사이라면 어디서든 줄을 바꿀 수 있다고 봅니다. 중국어와 일본어에는 단어 사이 공백이 없어서 그렇게 하지 않으면 줄을 바꿀 수 없기 때문이고, 그 규칙 자체는 옳습니다. 문제는 한국어에는 공백이 있다는 점입니다. 어절이 이미 공백으로 구분돼 있는데 굳이 글자 사이에서 끊을 이유가 없습니다.
word-break: keep-all이 정확히 이 상황을 위한 값입니다. “단어 안에서는 끊지 않는다” 는 뜻이고, 한국어에서는 공백으로 구분된 어절이 통째로 유지됩니다.
그런데 일본어 · 중국어에는 공백이 없습니다
여기가 이 속성의 진짜 함정입니다. keep-all은 “단어 안에서 끊지 않는다” 는 규칙이고, 공백이 없는 언어에서는 문단 전체가 단어 하나가 됩니다. 즉 끊을 자리가 하나도 없다는 선언이 됩니다.
결과는 눈에 보이는 고장입니다. 문단이 한 줄로 쭉 늘어나 컨테이너를 뚫고, 그리드의 칸이 그 폭을 그대로 받아 부풀고, 페이지에 가로 스크롤이 생깁니다. 한국어와 영어 화면은 멀쩡하기 때문에 다국어를 켜 보기 전에는 드러나지 않습니다. 기계 번역 위젯을 붙이거나 일본어 페이지를 추가하는 날 처음 발견하게 됩니다.
함께 써야 하는 두 줄
해결은 keep-all을 버리는 것이 아니라 비상구를 함께 두는 것입니다.
body {
word-break: keep-all; /* 한글 어절을 지킨다 */
overflow-wrap: anywhere; /* 끊을 데가 없으면 어디서든 끊는다 */
}
.card-grid {
display: grid;
/* 1fr 이 아니라 minmax(0, 1fr) — 칸이 내용 때문에 부풀지 않게 */
grid-template-columns: repeat(3, minmax(0, 1fr));
}
overflow-wrap의 값으로 break-word가 아니라 anywhere를 쓰는 것이 핵심입니다. 두 값 모두 필요할 때 글자 사이에서 끊어 주지만, anywhere만이 요소의 최소 폭 계산에도 반영됩니다. break-word는 “이 문단은 최소 이만큼 넓어야 한다” 는 계산에서는 여전히 문단 전체를 한 덩어리로 보기 때문에, 그리드 칸이 부푸는 문제는 그대로 남습니다.
같은 이유로 그리드 트랙에 minmax(0, 1fr)을 씁니다. 1fr은 사실 minmax(auto, 1fr)이고, 그 auto가 내용의 최소 폭을 바닥으로 삼습니다. 긴 문단 · 코드 블록 · URL 하나가 그 바닥을 밀어 올리면 트랙이 함께 늘어납니다.
예외를 두는 자리
모든 요소에 같은 규칙을 줄 필요는 없습니다. 코드 블록과 URL은 중간에서 끊기면 오히려 읽을 수 없게 되므로, 줄바꿈 대신 가로 스크롤을 그 요소 안에만 두는 편이 낫습니다.
pre, code, .url {
word-break: normal;
overflow-wrap: normal;
white-space: pre;
overflow-x: auto; /* 스크롤은 이 상자 안에서만 */
}
여유가 있다면 text-wrap: pretty(문단 끝 외톨이 단어 방지)와 text-wrap: balance(제목 줄 길이 균형)를 얹어도 좋습니다. 둘 다 지원하지 않는 브라우저에서는 아무 일도 일어나지 않으므로 안전하게 더할 수 있는 개선입니다.
레이아웃이 언어에 따라 무너지는 문제는 테마 · 플러그인 아카이브에서 더 다루고, 이미 운영 중인 사이트에서 이런 종류의 결함을 찾아내는 진단은 최적화 지원 사업에 포함돼 있습니다.
다음 회차
글자의 모양과 줄바꿈까지 정했으니, 이제 그 글자가 어떻게 도착하는가가 남았습니다. 다음 회차부터 세 편은 웹폰트입니다 — 먼저 자체 호스팅으로 무엇이 달라지는지부터 봅니다.