A4 인쇄 레이아웃, 41.7mm 를 나눗셈으로 짐작했다
빠진 칸이 41.7mm니 학생 6명이 더 들어간다고 셈했는데, 브라우저에서 재보니 2명이었다.
A4 한 장에 다 넣는 보고서는 어느 칸이 늘어나면 다른 칸이 대신 눌린다. 높이를 못 박아 놓은 종이라 넘치지도 않는다. 그냥 조용히 눌린다.
방과후 수업 활동 보고서가 그랬다. 위에서부터 머리글 · 정보표 · 출석부 · 강사 기록 · 활동 사진 · 기자재 점검 · 서명 순으로 들어간다. 학생이 많은 반에서 출석부가 길어지면 아래가 밀리고, 밀린 몫을 강사 기록 상자가 받아낸다. 14명짜리 반을 뽑아 보니 그 상자가 거의 0 높이가 돼서 라벨끼리 겹쳐 보였다.
그래서 코드에 상수가 하나 있었다.
const ROSTER_SAFE_MAX = 14; // 넘으면 인쇄 전에 경고를 띄운다
구조가 바뀌면서 자리가 생겼다
그날 오후에 지시가 왔다. "보고서를 회차마다 두 장으로 나누고, 둘째 장은 활동 사진으로."
그러면 활동 사진 칸이 첫 장에서 통째로 빠진다. 그 칸은 41.7mm 였다. 빠진 만큼 강사 기록 상자가 커진다. 그럼 몇 명까지 되나. 이렇게 셈했다.
빠져나간 공간 41.7mm ÷ 출석부 한 줄 6.6mm ≈ 6명
14 + 6 = 20 → 안전하게 19로 두자
상수를 19로 고치고 주석에 "출석부 한 줄이 6.6mm라 20명쯤에서 다시 찬다" 라고 적었다. 그럴듯했다.
그 숫자는 잰 게 아니었다
적어 놓고 보니 걸리는 게 있었다. 14는 화면에서 직접 확인한 값인데, 19는 머리로 나눈 값이었다. 그래서 브라우저에 물어봤다.
const px2mm = px => px / (96/25.4);
const zoom = parseFloat(getComputedStyle(sheet).zoom) || 1;
한줄 = px2mm(roster.getBoundingClientRect().height / zoom) / 행수;
지금_상자 = px2mm(box.getBoundingClientRect().height / zoom);
최소_상자 = 3줄 × 9.2pt × 1.62 + 안쪽여백; // 세 줄은 읽혀야 한다
더_넣을수있는_학생수 = (지금_상자 - 최소_상자) / 한줄;
결과는 이랬다.
한 줄 6.9mm ← 6.6 이 아니었다
지금 기록 상자 40mm
읽을 수 있는 최소 21mm
더 넣을 수 있는 수 2명 ← 6명이 아니었다
19가 아니라 16이었다. 세 배 틀렸다.
0까지 줄여도 된다고 가정한 칸
한 줄 높이가 6.6 대신 6.9였던 건 사소하다. 진짜 원인은 다른 데 있었다.
강사 기록 상자가 0까지 줄어들어도 된다고 가정하고 나눴다.
그 상자는 사람이 글을 적는 칸이다. 최소한 세 줄은 읽혀야 서류 구실을 한다. 그게 21mm다. 40mm 중에 내줄 수 있는 건 19mm뿐이었고, 나머지 21mm는 애초에 내 몫이 아니었다.
빠져나간 41.7mm를 전부 출석부에 쓸 수 있다고 본 게 잘못이었다. 그 공간은 이미 눌려 있던 상자가 되찾아 간 몫이었다.
판정 한 줄
이 숫자에 눈금이 있나.
인쇄 레이아웃은 눈금이 있는 일이다. mm도 pt도 다 잴 수 있고, 브라우저가 실제로 그린 값을 물어보면 알려준다. 잴 수 있는 것을 나눗셈으로 짐작하면 그럴듯한 숫자가 나와서 오히려 안 걸린다. 14는 실측이라 살아남았고 19는 계산이라 죽었다.
계산이 틀리는 자리는 대개 "이건 0까지 줄여도 되겠지" 하고 넘긴 항목이다. 공간을 나눌 땐 아무한테도 안 준 몫이 있는지부터 본다.