버그 추적

CSS Grid에서 박스가 삐져나오는 진짜 이유

실기기 412px에서 금액 박스가 밖으로 나갔다. 원인은 폭 지정이 아니라 그리드 항목의 min-width 기본값이었다.

CSS · 반응형 · 구독료

실기기 스크린샷으로 온 제보

운영자가 안드로이드 실기기(412px) 스크린샷과 함께 알려 왔습니다. 구독료 계산기의 금액 박스가 화면 밖으로 삐져나온다는 내용이었습니다.

개발 중에 390px와 1280px에서 확인했고 가로 스크롤은 0이었습니다. 그런데 실기기에서는 깨졌습니다. 폭을 조금 늘렸을 뿐인데 왜 더 나빠졌을까요.

범인은 폭 지정이 아니었다

처음 의심한 건 고정 폭이나 min-width를 어디 박아 둔 게 아닌가였습니다. 찾아보니 없었습니다. 결과 영역은 이렇게 생겼습니다.

.result-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

1fr은 "남은 공간을 나눠 가진다"는 뜻이니 넘칠 이유가 없어 보입니다. 하지만 그리드 항목의 min-width 기본값은 auto입니다. 이 값은 "내용의 최소 크기보다 작아지지 않는다"를 의미합니다.

즉 셀 안에 줄바꿈되지 않는 긴 금액(예: 4,214,463원)이 들어 있으면 그 문자열의 폭이 트랙의 하한이 됩니다. 1fr이 그보다 작아지려 해도min-width: auto가 막습니다. 결과적으로 트랙이 컨테이너를 밀어냅니다.

왜 390px에서는 안 보였나

390px에서는 그리드가 한 열로 떨어져 각 셀이 화면 폭을 그대로 씁니다. 412px에서는 두 열이 들어갈 만하다고 판단해 auto-fit이 열을 두 개로 잡고, 그 순간 각 셀의 가용 폭이 절반으로 줄면서 내용 최소 폭에 부딪힙니다.

화면이 넓어졌는데 더 깨지는 구조였던 겁니다. 기기 폭을 두 가지만 확인한 것이 놓친 원인이었고, 이후로는 중간 폭도 같이 보고 있습니다.

고치는 방법

그리드 항목에 min-width: 0을 주면 됩니다. "내용보다 작아져도 된다"고 명시하는 것이고, 그러면 1fr이 제대로 작동합니다. 넘치는 내용은 overflow 규칙으로 따로 다룹니다.

같은 이유로 플렉스 항목에도 자주 min-width: 0이 필요합니다. 플렉스에서는 min-width 기본값이 auto라 긴 텍스트에 text-overflow: ellipsis를 걸어도 말줄임이 나타나지 않고 컨테이너가 밀리는 현상이 생깁니다. 원인이 같습니다.

기억할 형태

"줄바꿈되지 않는 긴 문자열 + 그리드/플렉스 + 반응형"이 모이면 의심합니다. 금액, 날짜, URL, 파일명, 긴 영문 단어가 대표적입니다. 한국어는 어절 단위로 줄바꿈되어 덜 걸리지만, 숫자에 붙은 쉼표는 줄바꿈 지점이 아닙니다.

그리고 이 버그는 가로 스크롤 검사로 잡힙니다.문서의 scrollWidth와 clientWidth를 비교하는 한 줄이면 되고, 여러 폭에서 자동으로 돌리면 사람 눈보다 정확합니다. 지금은 페이지를 배포하기 전에 이 검사를 항상 돌립니다.

개발 노트 목록으로