getBoundingClientRect 로 정렬을 쟀는데 24px 어긋났다
박스 테두리는 같은데 글자는 24px 밀려 있었다. padding 이 안팎으로 갈린 탓이다.
정렬이 맞는지 눈으로 보지 말고 숫자로 확인하자며 콘솔을 여는 순간이 있다. 2026-08-16 에 내가 그랬다.
앱 화면 위쪽 머리글을 공용 컴포넌트로 갈아 끼우는 중이었다. 머리글의 글자와 본문의 글자가 같은 세로선에 서야 했다. 「맞는 것 같다」로 넘기지 않으려고 브라우저에서 좌표를 뽑았다.
머리글안쪽: { left: 255, right: 1023, w: 768 }
본문: { left: 255, right: 1023, w: 768 }
맞나: true
셋이 정확히 같았다. 「전부 255~1023px 로 정확히 일치한다」고 결론냈다.
몇 분 뒤 스크린샷을 봤다. 24px 어긋나 있었다.
컴포넌트가 아니라 잰 대상이 틀렸다
처음엔 새로 넣은 컴포넌트를 의심했다. 아니었다.
- 머리글은 여백(
padding)을 막대 바깥에 갖고 있었다 - 본문은 여백을 박스 안쪽에 갖고 있었다
그래서 박스의 테두리는 정확히 같은데 글자가 시작하는 자리는 24px 달랐다. 사람 눈에 보이는 건 테두리가 아니라 글자다. getBoundingClientRect().left 는 테두리를 알려주지 글자를 알려주지 않는다.
「측정했다」와 「맞는 것을 측정했다」가 갈린 자리다. 숫자가 나오면 검증한 기분이 드는데, 틀린 것을 재면 숫자는 오히려 확신을 준다. 눈으로만 봤으면 차라리 알아챘을 것이다.
같은 자리에서 두 번 더 헛짚었다. 여러 화면을 한 번에 재려고 iframe 여러 개에 걸쳐 좌표를 뽑았는데, iframe 안쪽 좌표와 바깥 좌표를 섞어서 빼는 바람에 값이 통째로 엉켰다. 그 숫자를 보고 「아직도 24px 어긋난다」라고 또 잘못 말했다. 게다가 그중 일부는 아직 로딩 중인 뼈대 화면을 재고 있었다 — querySelector('header') 가 뼈대 안의 다른 <header> 를 집어 왔기 때문이다.
측정 방법을 바꿨다
테두리가 아니라 글자가 서는 자리를 잰다.
// 박스만 — padding 이 다르면 통과해 버린다
e.getBoundingClientRect().left
// 글자가 서는 자리
e.getBoundingClientRect().left + parseFloat(getComputedStyle(e).paddingLeft)
더 확실한 건 실제 자식 요소를 재는 것이다. main > * 과 머리글의 제목을 비교하면 여백이 어디 붙었든 상관이 없다.
구조도 바꿨다
원인을 파고 보니 폭과 여백을 화면마다 손으로 적고 있었다. 그래서 어떤 화면은 max-w-2xl, 인쇄 막대는 max-w-5xl 이 되어 한 화면에 폭이 셋이었다. 클래스 묶음을 상수 하나로 모으고 머리글·본문·아래 메뉴가 그 한 곳을 같이 보게 했다. 손으로 적는 자리를 없애면 갈릴 수가 없다.
규칙도 한 줄 남겼다.
정렬은 박스가 아니라 글자를 잰다.
그 아래에 둘을 덧붙였다. iframe 좌표계를 섞지 마라, 로딩 화면을 재고 있는 건 아닌지 봐라. 셋 다 같은 날 한 번씩 밟은 것들이다.