모바일용 화면을 따로 만들면 깔끔해질 수 있지만 PC 화면에만 있는 항목이 빠지기 쉽다. 같은 업무를 두 폼으로 구현하면 저장 규칙과 오류 처리도 서로 달라질 수 있다. 이 프로젝트의 요청은 같은 자료와 작성 기능을 쓰면서 화면만 모바일에 맞추자는 방향이었다. 나는 그 원리를 원래 고객 코드와 분리한 작은 HTML·CSS 예제로 다시 구성했다. 실제 ERP의 모바일 검수 결과를 복제한 것이 아니라, 입력을 둘로 나누지 않는 구조를 살펴보는 공유 자료다.

화면 너비가 바뀌어도 입력은 새로 만들지 않는다

예제에는 품목 두 개와 수량·메모 입력이 있는 표 하나가 있다. 넓은 화면에서는 일반 표로 배치하고 작은 화면에서는 각 행을 카드처럼 배열하도록 CSS를 작성했다. 화면 크기에 따라 다른 폼을 생성하거나 값을 복사하지 않는다. 사용자가 입력한 요소의 식별자와 이름, 연결된 이벤트는 같은 문서 안에 한 번씩만 존재한다. 보기의 전환과 데이터의 전환을 분리하는 방식이다.

이 구조가 모든 모바일 문제를 해결하는 것은 아니다. 키보드가 차지하는 공간, 긴 오류 메시지, 선택 창의 위치와 초점 이동은 따로 확인해야 한다. 다만 작은 화면 전용 저장 함수를 새로 만들다가 필드 하나를 빠뜨리는 종류의 문제를 줄일 출발점이 된다. 대표가 휴대전화에서 현황을 보는 화면과 직원이 전표를 입력하는 화면도 필요한 정보가 다르므로, 같은 자료를 사용하더라도 읽기 순서는 역할에 맞게 정해야 한다.

제목과 입력의 연결을 함께 유지한다

PC의 열 제목이 작은 화면에서 눈에 덜 보이면 각 값이 무엇인지 알기 어려워진다. 예제는 카드 안에 수량과 메모의 시각적 라벨을 두고, 입력에는 행 제목과 열 제목의 식별자를 연결했다. 같은 수량 입력이 여러 개 있어도 어떤 품목의 수량인지 설명하려는 구조다. 필드 이름을 바꿀 때 라벨과 참조를 함께 바꿔야 한다는 점도 공유 파일에 적었다.

시각 라벨을 붙였다고 접근성 검수가 끝나는 것은 아니다. 표의 표시 방식을 바꾸면 실제 보조 기술이 구조를 읽는 방식도 확인해야 한다. 이 예제의 정적 검사는 참조 대상이 존재하는지와 중복 식별자가 없는지를 확인한다. 화면 낭독기, 키보드 조작, 인쇄와 실제 모바일 키보드를 사용한 결과는 아니다. 구조적으로 확인한 범위와 실제 사용에서 확인할 범위를 섞지 않는 것이 모듈 설명의 일부다.

코드와 구현 살펴보기

독립 예제 핵심 코드

:root { color-scheme: light; font-family: system-ui, sans-serif; color: #18342c; background: #f2f4ee; }
* { box-sizing: border-box; }
body { margin: 0; padding: 20px; }
main { max-width: 940px; margin: auto; }
h1 { font-size: clamp(1.5rem, 4vw, 2.2rem); }
p { line-height: 1.65; }
.table-wrap { max-width: 100%; overflow-x: auto; }
.work-table { width: 100%; border-collapse: collapse; background: white; }
.work-table caption { text-align: left; padding: 14px 0; font-weight: 700; }
.work-table th, .work-table td { padding: 12px; border-bottom: 1px solid #cad3c8; text-align: left; vertical-align: top; overflow-wrap: anywhere; }
.work-table thead { background: #e0e8dc; }
.work-table input { width: 100%; min-width: 0; min-height: 44px; padding: 8px; border: 1px solid #82988b; border-radius: 6px; font: inherit; font-size: 16px; color: inherit; }
.work-table input:focus-visible, button:focus-visible { outline: 3px solid #a75024; outline-offset: 3px; }
button { min-height: 44px; padding: 10px 18px; border: 0; border-radius: 8px; font: inherit; color: white; background: #214f3c; margin-top: 16px; }
.mobile-label { display: none; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; padding: 12px; background: white; }
@media (max-width: 700px) {
 body { padding: 12px; }
 .work-table { display: block; background: transparent; }
 .work-table caption { display: block; }
 .work-table thead { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
 .work-table tbody { display: grid; gap: 12px; }
 .work-table tr { display: grid; grid-template-columns: minmax(0,1fr); padding: 8px; background: white; border: 1px solid #cad3c8; border-radius: 10px; }
 .work-table td, .work-table tbody th { display: block; border: 0; min-width: 0; padding: 8px; }
 .mobile-label { display: block; font-weight: 600; font-size: .875rem; margin-bottom: 6px; }
}
@media print {
 body { background: white; }
 button, #result, .demo-note { display: none; }
}

저장 대신 현재 값을 로컬에서 읽어 본다

예제 버튼은 같은 폼의 현재 값을 읽어 아래에 JSON으로 표시한다. 계산·확정·서버 저장·외부 전송은 하지 않는다. 입력을 바꾸고 폭을 바꿔 보며 같은 필드가 결과에 이어지는지 살펴볼 수 있는 연결 지점이다. 실제 프로그램에 붙일 때는 기존 서버 저장과 검증 코드를 유지하고 이 버튼의 시연 동작을 업무 저장이라고 부르면 안 된다. 로컬 표시가 성공했다고 데이터베이스에 보관됐다는 뜻은 아니다.

코드는 결과를 텍스트로 표시하므로 입력한 메모를 HTML로 실행하지 않는다. 별도 의존성이나 원격 자산도 불러오지 않는다. 공유 ZIP을 같은 폴더에 풀고 예제 HTML을 열어 구조를 확인할 수 있다. 이번 발행에서는 소스의 필드·라벨 계약 아홉 항목과 JavaScript 문법을 확인했다. 브라우저 실화면은 필수 검사에서 제외한 사용자 지시에 따라 수행하지 않았으며, 실제 사용 전의 화면 검수를 대신했다고 설명하지 않는다.

서버 동작 없는 합성 예제. 실화면 조작 미검증.

모든 표를 카드로 바꾸지는 않는다

여러 열을 가로로 비교해야 하는 원가나 정산 표는 카드로 나누면 오히려 읽기 어려울 수 있다. 합쳐진 머리글, 행과 열을 동시에 비교하는 숫자, 긴 합계 관계가 있다면 가로 스크롤이나 별도 요약이 더 적합할 수 있다. 이 예제는 단순한 머리글과 행별 입력에 한정한다. 범용으로 공유한다는 말은 모든 표를 자동으로 바꾸겠다는 약속이 아니라 적용 조건과 바꿀 설정을 분명히 남긴다는 뜻이다.

도입할 때는 원래 필드 목록과 저장 payload를 먼저 적고, 같은 품목을 PC와 휴대전화 크기에서 편집하는 사례를 준비하자. 모든 필드가 남는지, 현재 값과 오류가 유지되는지, 한 번의 행동이 한 번만 실행되는지를 본다. 기능을 뺄지 더할지는 회사 업무에 따라 결정하되 화면이 작다는 이유만으로 필요한 업무 값을 조용히 빼지는 않는다. 제공 파일은 전부 합성 예제이며 회사 자료나 원래 프로그램의 코드를 포함하지 않는다.

독립 예제 ZIP 내려받기