거래명세서 인쇄 1페이지·다크모드 전환 버그 수정
목차
partner-portal 거래명세서 인쇄 화면에서 버그 두 개가 동시에 올라왔다. 하나는 한 페이지로 나와야 할 명세서가 두 페이지로 찍히는 문제, 다른 하나는 인쇄 다이얼로그를 닫고 나면 다크모드가 라이트 모드로 풀려버리는 문제. 변경된 파일은 뷰/스타일 1개다. 겉보기엔 작은 수정 같았는데, 파고들수록 브라우저 인쇄 컨텍스트의 동작 방식을 다시 짚어야 하는 케이스였다.
두 버그가 같은 화면에서 나왔지만 원인은 달랐다. 각각 따로 파악하고 따로 수정했다.
인쇄 컨텍스트가 까다로운 이유
브라우저에서 window.print()를 호출하거나 Ctrl+P를 누르면 렌더 엔진이 인쇄 컨텍스트로 전환된다. 이 시점에 @media print 블록이 올라오는데, 일반 화면 레이아웃과 다르게 동작하는 지점이 몇 가지 있다.
- 뷰포트 너비 기준이 달라진다. 화면에서
100vw이던 값이 용지 너비 기준으로 재계산된다. - flex/grid 일부 속성이 인쇄 컨텍스트에서 예상과 다르게 무너지는 경우가 있다.
- 화면에서
overflow: hidden이나 스크롤로 감춰진 영역이 인쇄에서는 실제 높이를 전부 차지한다. prefers-color-scheme기반 다크모드나 CSS 커스텀 프로퍼티가 인쇄 다이얼로그가 열려 있는 동안 상태가 꼬이는 경우가 있다.
거래명세서 화면은 화면용 레이아웃과 인쇄용 레이아웃을 같은 파일 안에서 함께 관리하고 있었다. @media print 블록 안에서 특정 wrapper의 높이 제한이 빠져 있어서 콘텐츠가 2페이지로 밀렸고, window.onafterprint 이벤트 처리가 없어서 인쇄가 끝난 뒤 테마 CSS 클래스 복원 로직이 아예 실행되지 않고 있었다.
실제 수정 내용
CSS 쪽은 @media print 안에서 컨테이너 높이와 페이지 분리 제어를 추가했다.
@media print {
.invoice-wrapper {
height: 100%;
max-height: 100vh;
overflow: hidden;
page-break-after: avoid;
break-after: avoid;
}
.no-print {
display: none !important;
}
}
스크립트 쪽은 window.onafterprint로 테마를 복원하도록 처리했다.
window.onafterprint = () => {
restoreTheme();
};
// Safari 구버전 폴백
const printMq = window.matchMedia('print');
printMq.addEventListener('change', (e) => {
if (!e.matches) restoreTheme();
});
beforeprint / afterprint 이벤트는 Safari 구버전에서 지원이 불완전한 경우가 있어서, matchMedia('print') 리스너를 같이 걸어 폴백을 뒀다. onafterprint가 먼저 터지는 브라우저에서는 거기서 처리되고, 그렇지 않은 환경에서는 matchMedia 리스너가 잡아준다. restoreTheme에 멱등 처리만 해두면 두 번 실행돼도 문제없다.
버그를 볼 때 보는 체크리스트
단순히 증상만 픽스하는 게 아니라 왜 발생했는지 원인을 먼저 파악하고, 비슷한 패턴이 다른 곳에도 있는지 확인한다. 위험한 케이스는 함께 수정한다.
| 항목 | 이유 |
|---|---|
| 같은 로직이 다른 경로에도 있는지 | 중복 코드가 있으면 한 쪽만 고쳐서 반쪽짜리 픽스가 됨 |
| 수정이 정상 케이스를 망가뜨리지 않는지 | edge 케이스 고치다 happy path 깨는 경우가 생각보다 많음 |
| 해당 화면에서 버그 직접 재현 후 확인 | "코드상 맞을 것 같다"는 검증이 아님 |
| 관련 숫자를 다른 화면과 cross-check | 명세서처럼 숫자가 핵심인 화면은 합계·항목 단위까지 비교 |
이번 케이스에서 인쇄 1페이지 버그는 CSS 몇 줄로 끝났는데, 다크모드 복원 누락은 onafterprint 미처리라는 별도 원인이었다. 같은 화면에서 나왔다고 원인도 같을 거라고 가정하면 하나만 고치고 넘어가게 된다. 각각 독립적으로 파악하는 게 중요하다.
파일 하나만 바뀌었다고 변경 범위가 작은 건 아니다. 인쇄 스타일은 일반 화면 QA에서 잘 안 잡히는 영역이라서, 이번에 관련 케이스를 정리해두고 수동으로 인쇄 미리보기까지 확인했다. 숫자 정합성도 관련 화면과 비교해서 틀린 게 없는지 대조했다.
사내 서비스를 만들다 보면 기능 하나가 화면 버튼 하나에 그치지 않는다는 걸 반복해서 체감한다. SQL 집계, 상태 머신, 예외 처리, 화면 렌더링, 권한 체크가 모두 얽혀 있어서 어느 하나만 빠뜨려도 숫자가 맞지 않거나 특정 환경에서 이상한 동작이 나온다. 금융/결제 도메인은 특히 숫자 하나가 틀리면 신뢰 문제로 직결되기 때문에 "대충 맞는 것 같다"로 넘어가면 나중에 반드시 더 큰 시간 비용으로 돌아온다.
엣지 케이스를 꼼꼼히 따지는 게 귀찮아 보여도, 같은 버그로 다시 오는 시간 비용이 훨씬 크다. 변경 전 현재 동작을 스크린샷이나 수치로 메모해두고, 수정 후 같은 케이스로 확인하고, 커밋 메시지는 "무엇을" 바꿨는지보다 "왜" 바꿨는지를 담으려고 의식적으로 노력한다. 작은 커밋을 자주 하는 것도 이 맥락에서인데, 논리적으로 독립된 단위로 쪼개두면 문제가 생겼을 때 어느 변경에서 깨졌는지 추적하는 시간이 확연히 줄어든다.
댓글 0
첫 댓글 달아줘.