표의 두 번째 칸에 설명용 줄바꿈을 넣으면 될 것 같았다. 하지만 합계 행의 두 번째 셀에는 금액이 있었다. 관리대장을 읽기 편하게 고친 작업에서, 칸의 위치보다 행 구조와 역할을 먼저 보아야 했던 이유를 남긴다.

숫자가 아래로 떨어진다는 요청에서 시작했다

과거 작업 대화에는 관리대장의 숫자가 아래로 내려가고 기본 폭이 너무 좁다는 요청이 있다. 당시 최종 답변은 금액·잔액·월계·누계를 한 줄로 표시하고 칸 너비와 여백, 오른쪽 정렬을 조정했다고 설명한다. 이번에는 그 장면을 새 화면 검수처럼 재현하지 않고, 현재 로컬의 표 생성 코드와 스타일을 읽었다. 원래 ERP의 중지 상태와 운영 자료는 그대로 두었다.

잔액을 확인하는 사람에게 숫자 한 덩어리는 읽기의 단위다. 자릿수가 다른 줄로 나뉘면 같은 금액을 다시 조합해야 한다. 그런데 설명 칸까지 줄바꿈을 막으면 긴 문장 하나가 표 전체를 밀어낼 수 있다. 이 요청은 모든 칸에 같은 규칙을 주는 방식으로 풀기 어려웠다.

이미 공개한 표 모듈은 본문 폭과 표의 스크롤 영역을 나누는 방법을 다룬다. 이번에 더 들여다본 지점은 그 안쪽이다. 일반 거래 행, 상세 설명 행, 합계 행이 서로 다른 셀 구조를 가지는데, 어느 칸을 설명으로 보고 어느 칸을 금액으로 다룰지 어떻게 정했는가.

보이는 열 번호와 셀의 순서가 달랐다

일반 행은 기록, 설명, 금액들 순서로 셀을 만든다. 이 행에서는 두 번째 셀이 설명이다. 반면 합계 행은 앞의 두 열을 하나의 머리글로 합친다. 그다음에 첫 금액 셀이 온다. 화면에서는 세 번째 열부터 금액이 보이지만, 행 안에서는 그 금액이 두 번째 자식 셀이다.

따라서 모든 행의 td:nth-child(2)를 설명 칸이라고 보면 합계의 첫 금액도 같은 규칙에 걸릴 수 있다. colspan은 머리글이 차지하는 열의 수를 늘리지만 그 자리에 자식 셀 두 개를 만드는 것은 아니다. 셀의 순서와 표에서 차지하는 열 위치를 같은 기준으로 읽으면 생기는 문제다.

이 위험을 실제 금액이 잘못 저장된 사건으로 쓰지는 않는다. 확인한 코드와 새 합성 표에서 두 구조가 다르다는 사실을 읽었다. 예제에서 일반 행의 두 번째 셀은 memo, 합계 행의 두 번째 셀은 money다. 같은 위치 선택자가 두 역할을 함께 고를 수 있음을 보여 주는 작은 반례다.

원래 구현은 설명 예외를 행 종류 안에 묶었다

확인한 스타일의 뒤쪽 보완 규칙은 금액 표의 셀에 한 줄 표시와 오른쪽 정렬을 주고, 일반 거래 행과 상세 행의 두 번째 셀에만 설명용 줄바꿈을 다시 허용한다. 합계 행 전체에 같은 설명 예외를 적용하지 않는다. 마지막 보완 규칙의 주석도 합친 머리글 뒤에 오는 첫 금액을 함께 다룬다고 적고 있다.

이 선택을 이해하려면 표 생성 코드도 함께 읽어야 했다. 일반 대장의 합계는 두 열짜리 머리글 뒤에 세 금액을 놓는다. 과거·현재 통합 대장은 같은 머리글 뒤에 여러 증감 항목과 잔액을 놓는다. 단순히 마지막 몇 셀만 숫자라고 가정하는 방식보다, 서로 다른 행과 금액 칸의 범위를 함께 보는 일이 필요했다.

원래 코드가 모든 셀에 의미 속성을 붙였다고 말하지는 않는다. 현재 소스는 행 종류와 위치를 조합한다. 이번 공유 예제에서는 그 판단을 다른 열 구성에서도 읽기 쉽게 만들려고 data-kind="memo"와 data-kind="money"를 명시했다. 원래 ERP를 이 방식으로 수정하거나 설치한 결과는 아니다.

폭을 넓히는 일과 금액의 표시 규칙을 나눴다

원래 종이형 표의 앞쪽 스타일에는 고정 배치와 긴 단어를 나누는 공통 규칙이 있고, 뒤의 보완에는 자동 배치와 금액의 줄바꿈 예외가 있다. 화면 전용 구간은 일반 대장과 통합 대장에 서로 다른 최소 폭과 여백을 준다. 선언 순서와 적용 범위를 함께 읽어야 현재 소스가 어떤 보완을 의도하는지 알 수 있었다.

오른쪽 정렬, 숫자 글리프의 폭을 맞추도록 요청하는 tabular-nums, 줄바꿈 방지와 충분한 칸 폭은 같은 설정이 아니다. 정렬만 바꿔도 금액이 쪼개질 수 있고, nowrap만 넣어도 표가 화면보다 넓어질 수 있다. 실제 글꼴과 계산된 배치는 화면에서 확인해야 한다. 선언이 있다는 사실만으로 모든 환경에서 읽기 문제가 해결됐다고 하지는 않았다.

기존 모듈의 스크롤 경계는 이때 함께 쓸 수 있다. 새 예제는 그 공개 CSS를 유지하고 금액·설명 역할 규칙만 더했다. 바깥 본문을 숨겨 잘라내거나 모든 숫자를 축약하지 않는다. 예제의 최소 폭은 설명을 위한 시작값이며 원래 ERP의 폭이나 모든 대장에 맞는 규격을 뜻하지 않는다.

합계 행을 포함한 독립 예제를 남겼다

아래 전체 HTML은 기존 표 모듈의 공개 래퍼와 CSS를 재사용한 새 합성 예제다. 두 거래 행과 두 열을 합친 합계 머리글을 둔다. 설명은 줄바꿈을 허용하고 금액은 역할 속성으로 한 줄 표시를 요청한다. 합계의 첫 금액도 다른 금액과 같은 money 표시를 가진다.

숫자는 미리 넣은 표시 문자열이다. 금액 계산, 반올림, 서버 저장이나 실제 장부 대조를 하지 않는다. 0도 문자열로 남기며 공백이나 누락과 자동으로 바꾸지 않는다. 표의 읽기 규칙을 설명하려고 실제 업체나 담당자, 날짜별 거래를 가져올 필요는 없었다.

코드를 복사해 독립 HTML로 열어 볼 수 있고, 본문 안의 예시도 같은 자료를 사용한다. 기존 표 모듈 본문과 버전은 그대로 둔다. 같은 스크롤 모듈을 이름만 바꾸어 새 모듈로 등록하거나 별도 ZIP을 늘리지 않았다. 필요한 보완은 이 글의 역할 속성과 합계 행 예제로 공개한다.

코드와 구현 살펴보기

독립 합성 전체 HTML · 복사해 재사용 가능

<!doctype html><html lang="ko"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>합계 행에서도 금액은 한 덩어리로</title><style>body{margin:0;padding:18px;font:16px/1.6 system-ui;color:#173d36}*{box-sizing:border-box}.comparison-block { min-width: 0; max-width: 100%; }
.comparison-scroll {
  width: 100%;
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  border: 1px solid #cbd2cd;
}
.comparison-scroll:focus-visible {
  outline: 3px solid #2d6a51;
  outline-offset: 3px;
}
.comparison-scroll table {
  width: 100%;
  min-width: 40rem;
  border-collapse: collapse;
  line-height: 1.6;
}
.comparison-scroll caption {
  padding: 1rem;
  text-align: left;
  font-weight: 700;
}
.comparison-scroll :is(th, td) {
  padding: 1rem;
  border-bottom: 1px solid #dce0dd;
  text-align: left;
  vertical-align: top;
  overflow-wrap: anywhere;
}
.comparison-scroll thead th { background: #edf2ee; }
/* If the parent is a grid, use minmax(0, 1fr) for its content track. */
/* Synthetic addition: cell roles remain meaningful after colspan. */
.money-example table { min-width: 48rem; }
.money-example [data-kind="money"] {
  white-space: nowrap;
  overflow-wrap: normal;
  word-break: normal;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.money-example [data-kind="memo"] {
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: left;
}
.money-example .summary th { text-align: left; }
</style><section class="comparison-block money-example"><h1 id="money-title">합계 행에서도 금액은 한 덩어리로</h1><p id="money-hint">합성 표시 예제입니다. 표 영역을 좌우로 움직여 전체 열을 확인하세요.</p><div class="comparison-scroll" role="region" tabindex="0" aria-labelledby="money-title" aria-describedby="money-hint"><table><caption>실제 업체 자료가 없는 합성 숫자</caption><thead><tr><th scope="col">기록</th><th scope="col">설명</th><th scope="col">발생</th><th scope="col">처리</th><th scope="col">잔액</th></tr></thead><tbody><tr class="entry"><th scope="row">R-A</th><td data-kind="memo">설명은 필요하면 여러 줄로 읽습니다. 금액은 같은 규칙으로 보존합니다.</td><td data-kind="money">1,234,567</td><td data-kind="money">0</td><td data-kind="money">1,234,567</td></tr><tr class="entry"><th scope="row">R-B</th><td data-kind="memo">설명은 필요하면 여러 줄로 읽습니다. 금액은 같은 규칙으로 보존합니다.</td><td data-kind="money">0</td><td data-kind="money">34,567</td><td data-kind="money">1,200,000</td></tr><tr class="summary"><th scope="row" colspan="2">합계</th><td data-kind="money">1,234,567</td><td data-kind="money">34,567</td><td data-kind="money">1,200,000</td></tr></tbody></table></div><p>미리 입력한 문자열이며 계산·저장·실제 장부 대조는 하지 않습니다.</p></section></html>
합성 표시 문자열 · 계산·저장·브라우저 실검수 없음

구조 검사에서 확인한 것과 화면에서 남은 것

새 한영 HTML을 파서로 읽어 언어마다 아홉 항목, 총 18개 구조 조건을 확인했다. 열 머리글은 다섯 개이며 colspan을 펼쳐 세어도 모든 본문 행이 다섯 열을 차지한다. 일반 행과 합계 행의 두 번째 셀 역할이 다르고, 첫 합계 금액에 money 표시가 남는지 확인했다. 금액 문자열과 0이 온전히 남는지도 대조했다.

초점 영역이 가리키는 제목·안내의 식별자와 중복 여부, 위치 선택자에 기대지 않는 역할 규칙, 외부 주소·폼·스크립트가 없는 범위도 확인했다. 이는 실제 새 HTML의 구조와 CSS 선언을 읽은 검사다. CSS 배치 엔진이나 원래 React 화면 시험, 브라우저를 실행한 결과는 아니다.

원래 스타일에는 인쇄 전용 규칙도 별도로 있다. 화면에서 폭을 넓혔다고 인쇄 용지나 PNG·PDF 출력까지 맞았다고 보고하지 않았다. 실제 적용에서는 긴 설명과 큰 금액, 음수 표기, 확대된 글자, 합계·통합 행, 출력 매체를 함께 살펴야 한다. 이번에는 그 검수를 완료했다고 주장하지 않고 확인할 조건으로 남긴다.

열 수를 바꾸기 전에 행의 역할을 읽는다

다른 회사의 대장에 적용할 때는 거래 행 하나만 고치고 끝내지 않는다. 이월·일계·월계·누계와 상세 행이 셀을 몇 개 만들고 어느 칸을 합치는지 먼저 적는다. 이어 설명과 금액 역할을 지정하고, 최소 폭과 스크롤 책임을 정한다. 셀 역할을 바꾸는 작업이 계산 값이나 저장 필드를 건드리지 않는지도 함께 살핀다.

행 구조를 코드로 읽으면 단순히 칸을 넓혔다는 답보다 변경의 이유를 정확히 설명할 수 있다. 두 번째 칸이라는 위치와 설명이라는 역할은 어떤 행에서는 같고 다른 행에서는 다르다. 이 차이를 남겨 두면 나중에 열이 추가될 때도 처음의 가정을 다시 확인할 수 있다.

기존 표 모듈에서 바깥 스크롤과 표 제목·머리글 구조를 확인하고, 이번 예제에서는 합계 행의 역할을 이어 보면 된다. 입력 표를 카드로 바꾸는 문제는 별도의 단일 입력 모듈에 맡겼다. 숫자가 잘 보이게 만드는 작업도 실제 업무 값과 읽는 구조를 각각 지켜야 계속 수정할 수 있다.