Chapter 09

폼

웹사이트에서 사람이 가장 많이 "일하는" 화면은 폼이다. 모임을 신청하고, 주소를 적고, 비밀번호를 바꾼다. 그런데 폼만큼 사람을 쉽게 지치게 하는 화면도 드물다. 적으려는 순간 안내 글이 사라지고, 다 적고 나서야 맨 위에 붉은 글이 뜨고, 하이픈을 안 넣었다고 번호를 거절당한다. 이 장은 폼을 사람과 화면이 주고받는 짧은 대화로 보고, 그 대화를 망치는 작은 결정들을 하나씩 고친다. 그리고 책방 E의 모임 신청 폼을 처음부터 다시 짠다.

폼은 짧은 대화다

사람이 정보를 적어 보내는 화면을 폼(Form)이라고 한다. 웹 페이지 대부분은 읽히기만 하지만, 폼은 읽는 사람에게 일을 시킨다. 폼 안에서 한 가지 정보를 받는 상자를 입력 칸(Input field)이라고 하고, 칸이 무엇을 받는지 알려 주는 이름표를 라벨(Label)이라고 한다. 칸 안에 흐린 글씨로 미리 적혀 있다가 입력을 시작하면 사라지는 글은 자리표시자(Placeholder)다.

폼을 대화로 생각하면 좋은 폼의 조건이 쉽게 보인다. 좋은 상대는 무엇을 묻는지 분명히 말하고(라벨), 대답하는 동안 끼어들지 않고(검증 시점), 잘못 알아들었을 때는 바로 그 자리에서 어떻게 고치면 되는지 알려 준다(오류 위치와 문구). 그리고 필요 없는 것을 묻지 않는다(칸 줄이기). 아래 그림은 책방 E의 옛 웹사이트에 있던 모임 신청 폼을 다시 그린 것이다. 2019년쯤 산 템플릿에 딸려 온 폼이라 이 장에서 고칠 거의 모든 문제가 들어 있다.

책방 E · 모임 신청 입력 정보를 다시 확인하십시오. 이름 이메일 01012345678 생년월일(YYYYMMDD) 주소 참가 모임 선택 ▾ 3 보내기 * 표시는 필수 항목입니다 1 오류가 맨 위에 한 줄어느 칸이 틀렸는지 말하지 않는다 2 하이픈 없는 번호는 거절010-0000-0000 형식만 받는다 3 적고 나면 무슨 칸인지 모름"3"은 본인 포함일까? 4 필요 없는 칸 셋이메일·생년월일·주소 별표 설명은 맨 아래에 있지만 정작 칸에는 별표가 없다
그림 1. 책방 E의 옛 모임 신청 폼(다시 그림). 칸이 일곱 개인데 라벨은 하나도 없고, 흐린 자리표시자가 그 일을 대신한다. 이미 적은 두 칸(전화번호, 인원)은 무슨 칸이었는지 알 수 없다. 제출하면 맨 위에 "다시 확인하라"는 한 줄이 뜬다. 이 장의 절들이 번호 순서와 상관없이 이 문제들을 하나씩 다룬다.

그림 속 문제 가운데 어느 것도 "디자인이 촌스럽다" 같은 취향의 문제가 아니다. 모두 사람이 폼을 채우는 동안 머릿속에서 무엇을 기억해야 하는지, 눈이 어디로 가야 하는지, 손가락이 몇 번 움직여야 하는지의 문제다. 그래서 폼 디자인은 겉모습보다 순서와 시점을 설계하는 일에 가깝다. 폼 설계의 고전으로 꼽히는 책들, 예를 들어 캐럴라인 재럿과 제리 개프니의 『Forms that Work』(2008)와 루크 로블레프스키의 『Web Form Design: Filling in the Blanks』(2008)도 폼을 "질문과 대답의 대화"로 보는 데서 출발한다.

폼은 접근성 기준이 가장 촘촘한 곳 웹 콘텐츠 접근성 지침 WCAG 2.2(W3C, 2023)의 성공 기준 가운데 여러 개가 폼을 직접 겨냥한다. 1.3.1 정보와 관계(라벨과 칸이 코드로 이어져야 한다), 1.3.5 입력 목적 식별(개인 정보 칸의 목적을 기계가 알 수 있게, autocomplete), 3.3.1 오류 식별(어느 칸이 왜 틀렸는지 글로), 3.3.2 레이블 또는 지시(라벨과 안내), 3.3.3 오류 수정 제안(고칠 방법을 알려 준다), 3.3.7 중복 입력(2.2에 새로 생김, 같은 과정에서 이미 적은 것을 다시 적게 하지 않는다)이다. 이 장은 시각 디자인 쪽에서 이 기준들을 만나고, 화면 낭독기와 키보드로 쓰는 폼은 11장에서 다시 본다.

라벨과 자리표시자

칸 안에 흐린 글씨로 "이름"이라고 적어 두면 라벨이 따로 필요 없어 보인다. 화면도 깔끔해지고 세로 공간도 아낀다. 그래서 많은 템플릿이 자리표시자를 라벨 대신 쓴다. 문제는 자리표시자가 입력을 시작하는 순간 사라진다는 데 있다. 대화로 치면, 질문을 한 번 말한 뒤 대답을 시작하자마자 질문을 지워 버리는 상대다.

아래 목업에서 세 가지 방식을 바꿔 가며 직접 적어 본다. "인원" 칸에는 "본인 포함, 최대 4명"이라는 안내가 있다. 숫자를 적고 나서 그 안내가 어디에 남는지 본다. "예시 값 채우기"를 누르면 세 칸이 채워진 상태, 곧 제출 직전에 다시 훑어보는 순간이 된다.

SIMULATOR

라벨, 자리표시자, 떠오르는 라벨

책방 E

모임 신청

숫자만 적어도 된다
본인 포함, 최대 4명
지금 보이는 칸 이름—
지금 보이는 안내 글—
안내 글자의 대비(흰 바탕)—
다시 훑어볼 때 보이는 것—
해볼 것: ① "자리표시자만"에서 인원 칸에 3을 적는다. "본인 포함"이라는 안내가 사라져, 셋이 나를 포함한 수였는지 기억에 기대야 한다. 휴대폰처럼 칸이 좁으면 긴 자리표시자는 처음부터 잘려 보이기도 한다. ② "예시 값 채우기"를 누른다. 세 칸에 이름도 안내도 없이 값만 남는다. ③ "자리표시자를 진하게"를 켜고 "비우기"를 누른다. 대비는 좋아졌지만 이번에는 빈 칸이 이미 채워진 칸처럼 보인다. ④ "칸 위 라벨"로 바꿔 같은 일을 해 본다. ⑤ "떠오르는 라벨"은 이름은 남기지만 안내 글은 여전히 자리표시자에 들어 있어 적는 순간 사라진다. (흰 바탕 기준 대비는 ART.contrast로 계산한 값이다. 기본 자리표시자 색은 많은 브라우저가 쓰는 흐린 회색에 가깝게 잡았다.)

자리표시자만 둔 칸은 세 번 실패한다. 첫째, 기억. 적는 동안 질문과 안내가 사라지므로 사람이 그것을 머리에 들고 있어야 한다. 짧은 이름 칸이면 괜찮지만 "본인 포함" 같은 조건이 붙으면 금세 잊는다. 둘째, 대비. 자리표시자는 "아직 안 적었다"는 것을 보여 주려고 일부러 흐리게 칠한다. 그래서 대부분 글자 대비 기준(WCAG 1.4.3, 4.5:1)에 못 미친다. 진하게 칠하면 이번에는 이미 채운 칸과 구별이 안 된다. 흐린 것이 자리표시자의 정체성이라 둘을 다 얻을 수 없다. 셋째, 검토. 다 채운 폼을 제출 전에 훑어볼 때 칸마다 값만 있고 이름이 없다. 화면 낭독기 사용자에게는 더 나쁘다. 자리표시자는 칸의 이름으로 읽히지 않을 수도 있고, 읽히더라도 값을 적은 뒤에는 사라진다.

칸 위 라벨 이름 휴대폰 번호 인원 눈이 한 방향으로 내려간다 좁은 화면에서도 칸이 넓다 칸 왼쪽 라벨 이름 휴대폰 번호 인원 눈이 좌우로 오간다 긴 라벨이 칸을 밀어낸다 칸 안 라벨 이름 01012345678 3 이건 무슨 칸? 세로 공간은 가장 적다 적으면 이름이 사라진다
그림 2. 라벨을 두는 세 자리. 칸 위 라벨은 라벨과 칸이 한 덩어리로 묶이고 눈이 아래로만 움직인다. 칸 왼쪽 라벨은 넓은 화면에서 세로 공간을 아끼지만 눈이 좌우로 오가고, 좁은 화면에서는 칸을 좁게 만든다. 칸 안 라벨(자리표시자)은 공간이 가장 적게 들지만 적는 순간 이름을 잃는다.

칸 위 라벨은 좁은 휴대폰 화면에서 특히 유리하다. 라벨이 아무리 길어도 칸의 폭을 빼앗지 않고, 화면 글자를 크게 키운 사람에게도 라벨과 칸이 한 줄씩 내려온다. 칸 왼쪽 라벨은 넓은 화면에서 긴 폼의 세로 길이를 줄이고, 라벨을 훑으며 원하는 칸을 찾기 좋아 관리자 화면처럼 같은 폼을 매일 쓰는 사람에게 맞기도 하다. 라벨 위치에 관한 작은 시선 추적 연구들(예: 마테오 펜조, "Label Placement in Forms", UXmatters, 2006)은 칸 위 라벨이 가장 빨리 훑어진다고 보고했지만 참가자가 적은 연구라, "칸 위 라벨은 대부분의 상황에서 무난하다" 정도로 받아들이는 것이 좋다.

그림 2와 시뮬레이터의 세 번째 방식인 떠오르는 라벨(Floating label)은 둘의 타협이다. 처음에는 자리표시자처럼 칸 안에 있다가, 칸을 누르면 작게 줄어 칸 위쪽 가장자리로 올라간다. 이름은 남지만 글자가 작아지고, 안내 글을 둘 자리가 따로 없어 결국 안내가 자리표시자로 돌아가기 쉽다. 쓰더라도 안내 글은 칸 밖에 둔다.

<label for="count">인원</label>
<p id="count-hint">본인 포함, 최대 4명</p>
<input id="count" inputmode="numeric" aria-describedby="count-hint">

코드에서 라벨은 <label for>로 칸과 이어 준다. 그러면 라벨 글자를 눌러도 칸에 커서가 들어가 누를 자리가 넓어지고(7장의 터치 타깃), 화면 낭독기는 칸에 들어갈 때 라벨을 읽는다. 안내 글은 aria-describedby로 이어 칸의 설명으로 함께 읽히게 한다. 자리표시자는 예시가 정말 도움이 될 때(예: "예: 2028-03-04") 라벨과 별도로 덧붙이는 보조 수단으로만 쓴다.

라벨은 질문이 아니라 명사로 라벨은 "성함을 입력해 주시겠어요?"보다 "이름"처럼 짧은 명사가 빨리 읽힌다. 설명이 필요하면 라벨 아래 안내 글로 따로 둔다. 라벨에는 콜론(:)을 붙이지 않는 편이 깔끔하고, 한 폼 안에서는 말투와 길이를 맞춘다. 같은 정보를 사이트 곳곳에서 묻는다면 라벨도 같아야 한다. 한 곳은 "연락처", 다른 곳은 "휴대폰 번호", 또 다른 곳은 "전화"라고 쓰면 사람들은 셋이 다른 것인지 고민한다. 라벨 글자는 본문보다 조금 작아도 되지만 굵게 두어 칸보다 먼저 읽히게 한다. 6장에서 만든 글자 크기 단계 가운데 한 칸을 라벨 몫으로 정해 두면 페이지마다 흔들리지 않는다.

칸의 폭은 답의 길이를 말한다

칸의 생김새도 질문의 일부다. 우편번호 칸이 이름 칸만큼 넓으면 사람들은 잠깐 망설인다. 길게 적어야 하나? 반대로 주소 칸이 짧으면 동 이름까지만 적고 멈춘다. 칸의 폭은 기대하는 답의 길이를 말없이 알려 주는 단서다. 여러 줄을 받는 칸(<textarea>)이면 높이도 같은 말을 한다. 세 줄 높이의 칸은 "몇 문장 정도"를, 한 줄짜리 칸은 "한 줄로"를 말한다.

아래 목업은 칸 다섯 개짜리 폼이다. 칸 폭을 정하는 세 가지 방식을 바꾸고, 목업의 폭을 360px 휴대폰에서 넓은 화면까지 늘여 본다. 각 칸에는 예시 값이 들어 있다.

SIMULATOR

칸 폭이 주는 단서

값이 잘린 칸—
가장 넓은 칸 ÷ 가장 좁은 칸—
길이 단서—
해볼 것: ① "모두 같은 폭"에서 우편번호와 인원 칸을 본다. 다섯 자리, 한 자리를 받는 칸이 이름 칸만큼 넓어 길이 단서가 없다. ② "답 길이에 맞춤"으로 바꾼다. 우편번호는 짧게, 휴대폰 번호는 중간, 남길 말은 가장 넓고 높게. 칸의 모양만으로 무엇을 얼마나 적을지 짐작된다. ③ "모두 좁게"로 바꾼다. 휴대폰 번호와 남길 말이 잘려, 적은 것을 다시 확인할 수 없다. 단서가 거짓말을 하는 경우다. ④ 목업 폭을 300까지 줄인다. 맞춤 방식에서도 긴 칸은 화면 폭에 맞춰 줄어든다. (칸 폭은 각 칸에 흔히 들어갈 가장 긴 값의 글자 폭에 안쪽 여백을 더한 이 장의 규칙이다. 짧은 칸도 7장의 터치 타깃을 생각해 72px보다 좁게 만들지 않았다.)

칸 폭을 답 길이에 맞추면 폼이 들쭉날쭉해 보인다는 걱정이 있다. 하지만 모든 칸이 같은 왼쪽 정렬선에서 시작하는 한 오른쪽 끝이 다른 것은 어수선해 보이지 않는다(CompositionBook 12장의 정렬). 다만 이 원칙은 넓은 화면에서 의미가 크다. 휴대폰처럼 폭이 360px 안팎인 화면에서는 대부분의 칸이 화면 폭에 가까워지고, 그래도 괜찮다. 우편번호, 인원, 카드 유효기간처럼 정말 짧은 칸만 좁게 두는 정도로 충분하다.

폭이 길이를 알려 주는 것처럼, 칸을 나누는 방식도 형식을 알려 준다. 전화번호를 세 칸(010 / 1234 / 5678)으로 나누면 형식은 분명해지지만, 붙여 넣기가 깨지고 칸 사이를 옮겨 다녀야 한다. 대부분의 경우 한 칸으로 받고 형식은 기계가 맞추는 편이 낫다. 다음 두 절이 그 이야기다.

알맞은 키보드, 자동 완성

휴대폰에서 폼을 채울 때 가장 많이 하는 일은 키보드를 바꾸는 일이다. 한글 자판에서 숫자를 적으려면 "123"을 누르고, 이메일의 @를 찾으려면 영문 자판으로 갔다가 기호 자판으로 간다. 웹 페이지는 칸마다 어떤 키보드를 띄울지 브라우저에 알려 줄 수 있다. 세 가지 속성이 그 일을 한다.

속성하는 일예
type칸이 받는 값의 종류. 키보드뿐 아니라 브라우저의 검사와 의미도 바뀐다.email(@가 있는 자판), tel(전화 숫자판), url, search
inputmode값의 종류는 그대로 두고 키보드만 고른다.numeric(숫자판), decimal(소수점 포함), tel, email
autocomplete칸의 목적을 알려 브라우저가 저장된 정보를 제안하게 한다.name, tel, email, postal-code, one-time-code(문자로 받은 인증번호)

인원이나 인증번호처럼 숫자로만 된 값이라도 type="number"는 조심해서 쓴다. 이 형식은 "수량"을 위한 것이라 앞자리 0을 지우거나, 마우스 휠에 값이 바뀌거나, 칸 옆에 작은 위아래 화살표를 붙이는 등 브라우저마다 다르게 군다. 우편번호, 인증번호, 카드 번호처럼 숫자로 된 글자는 type="text"에 inputmode="numeric"을 쓰는 편이 안전하다.

아래 휴대폰 목업에서 칸의 종류를 고르고, 속성을 "기본"과 "알맞게"로 바꿔 본다. 키보드가 바뀌는 모습과, 그 값을 적는 데 드는 탭 수의 어림값을 비교한다.

SIMULATOR

칸이 부르는 키보드

뜨는 키보드—
값을 적는 탭 수(어림)—
코드—
해볼 것: ① "휴대폰 번호"를 "기본"으로 둔다. 한글 자판이 떠서 "123"을 한 번 누르고 숫자를 적어야 한다. ② "알맞게"로 바꾼다. 전화 숫자판이 뜨고 키가 크다. 저장된 정보가 있으면 키보드 위에 번호 제안이 떠서 한 번에 끝난다. ③ "이메일"과 "인증번호"로 같은 비교를 한다. 인증번호는 one-time-code 덕에 문자로 받은 번호가 제안된다. ④ "브라우저에 저장된 정보가 있다"를 끄면 제안이 사라진다. (키보드 모양과 제안 방식은 운영 체제와 키보드 앱마다 다르다. 이 목업은 대표적인 모양을 단순하게 그렸다. 탭 수는 자판 전환과 글자 하나를 각각 한 번으로 센 어림값이다. 한글은 자모 하나를 한 번으로 셌다.)

자동 완성은 작은 기능 같지만 폼의 수고를 가장 크게 줄인다. 이름, 휴대폰 번호, 이메일, 주소는 대부분의 브라우저가 저장해 두었다가 제안할 수 있다. 그러려면 칸이 무엇을 받는지 표준 이름(autocomplete 값)으로 알려 줘야 한다. WCAG 2.2의 1.3.5 입력 목적 식별(AA)이 바로 이것을 요구한다. 기억이나 손 움직임에 어려움이 있는 사람에게 자동 완성은 편의가 아니라 폼을 끝낼 수 있느냐의 문제다. 반대로 autocomplete="off"를 습관처럼 붙이는 템플릿이 많은데, 정말 저장하면 안 되는 값이 아니라면 떼는 것이 좋다.

같은 이유로, 한 과정 안에서 이미 받은 정보를 다시 적게 하지 않는다. 배송지와 청구지가 같으면 "위와 같음"을 고르게 하고, 앞 단계에서 적은 이메일을 다음 단계에서 또 묻지 않는다. WCAG 2.2에 새로 들어온 3.3.7 중복 입력(A)이다. 인증 과정에서 기억력 퍼즐(예: 비밀번호를 붙여 넣지 못하게 막기)을 요구하지 않는 3.3.8 접근 가능한 인증(AA)도 같은 결의 기준이다.

입력 글자는 16px 이상으로 휴대폰의 일부 브라우저(대표적으로 iOS의 Safari)는 글자 크기가 16px보다 작은 입력 칸을 누르면 화면을 자동으로 확대한다. 칸을 다 채우고 나면 사람이 직접 화면을 다시 줄여야 해서 매우 성가시다. 입력 칸의 글자를 16px 이상으로 두면 이 확대가 일어나지 않는다. TypeBook에서 정한 책방 E의 본문 크기(17px 안팎)를 입력 글자에도 그대로 쓰면 저절로 해결된다. 확대를 막으려고 페이지 전체의 확대를 금지하는 설정(maximum-scale=1, user-scalable=no)을 쓰는 것은 확대가 필요한 사람을 막는 일이라 피한다(2장).

형식은 기계가 맞춘다

그림 1의 옛 폼은 휴대폰 번호를 "010-0000-0000" 형식으로만 받았다. 하이픈을 빼고 적으면, 띄어 쓰면, 붙여 넣은 번호에 국가 번호가 붙어 있으면 모두 거절했다. 하지만 이 네 가지는 모두 같은 번호다. 사람에게 기계의 형식을 강요하는 대신, 기계가 사람의 여러 형식을 받아 한 형식으로 정리하면 된다. 숫자만 뽑아내고, +82로 시작하면 0으로 바꾸고, 자리 수를 확인한 뒤 저장할 때 하이픈을 넣는다. 인터넷 초기의 통신 규약 문서(RFC 761, 1980)에 실려 널리 알려진 "보낼 때는 엄격하게, 받을 때는 너그럽게"라는 원칙이 폼에서도 통한다.

아래에서 같은 번호를 여러 모양으로 넣어 본다. 첫 번째 단추 묶음으로 검사 방식을, 두 번째 묶음으로 오류 문구의 방식을 바꾼다.

SIMULATOR

엄격한 칸, 너그러운 칸

책방 E
판정—
저장되는 값—
보기 여섯 개 중 맞게 판정한 것—
해볼 것: ① "엄격"에서 보기 단추를 차례로 누른다. 같은 번호 다섯 가지 중 넷이 거절된다. ② "너그럽게"로 바꾼다. 다섯 가지가 모두 같은 값 010-1234-5678로 저장되고, 자리 수가 모자란 마지막 보기만 거절된다. ③ 마지막 보기에서 문구를 "고칠 방법을 말하는 문구"로 바꾼다. 무엇이 틀렸고 어떻게 고치면 되는지가 한 문장에 들어간다. ④ 칸에 직접 이것저것 적고 "확인"을 눌러 본다. (너그러운 검사는 이 장의 단순 규칙이다: 숫자만 뽑고, +82로 시작하면 앞의 82를 0으로 바꾸고, 01로 시작하는 10~11자리면 받는다. 실제 서비스는 유선 전화나 해외 번호도 생각해야 한다.)

"형식이 올바르지 않습니다"는 오류 문구의 대표적인 실패다. 무엇이 틀렸는지도, 어떻게 고치는지도 말하지 않는다. 좋은 오류 문구는 세 가지를 한 문장에 담는다. 어느 칸인지(칸 바로 아래에 두면 저절로 해결된다), 무엇이 문제인지, 어떻게 고치는지. "휴대폰 번호가 한 자리 모자랍니다. 010으로 시작하는 11자리를 적어 주세요."처럼. WCAG 2.2의 3.3.1 오류 식별(A)은 앞의 둘을, 3.3.3 오류 수정 제안(AA)은 마지막 하나를 요구한다.

오류 문구는 사람을 탓하지 않는다 "잘못 입력하셨습니다", "유효하지 않은 값", "오류 코드 E-1042" 같은 문구는 사람을 탓하거나 기계의 말을 그대로 옮긴다. 오류는 대개 폼이 질문을 분명히 하지 못해서 생긴다. 문구는 짧고 구체적으로, 사람이 할 다음 행동을 말한다. "이름을 적어 주세요", "인원은 1명에서 4명까지 신청할 수 있습니다". 느낌표와 대문자, 붉은 글씨를 겹쳐 쓰지 않는다. 오류는 이미 충분히 불편하다. 색만으로 오류를 알리지 않는 것도 잊지 않는다. 붉은 테두리만 바뀌면 제2색각 사람에게는 잘 안 보인다(ColorBook 13장). 아이콘과 글자를 함께 둔다.

언제, 어디에 알릴까

값이 맞는지 확인하는 일을 검증(Validation)이라고 하고, 사람이 폼을 다 채워 보내기 전에 칸마다 그 자리에서 알려 주는 방식을 인라인 검증(Inline validation)이라고 한다. 인라인 검증에는 두 가지 결정이 따른다. 언제 알릴지(글자 하나를 칠 때마다, 칸을 떠날 때, 제출할 때)와 어디에 알릴지(폼 맨 위 요약, 칸 바로 아래, 둘 다)다.

아래는 책방 E의 새 모임 신청 폼 시안이다. 두 결정을 바꿔 가며 직접 채우고 틀려 본다. "번호를 한 자씩 적어 보기"를 누르면 휴대폰 번호 칸에 사람이 한 글자씩 치듯 숫자가 들어간다. 오른쪽 아래 숫자는 적는 도중에 뜬 오류와, 고쳤는데도 남아 있던 오류를 센다.

SIMULATOR

오류를 알리는 시점과 자리

책방 E

모임 신청

네 칸 모두 적어 주세요.

참가할 모임
하이픈은 넣어도 빼도 된다
본인 포함, 1~4명
적는 도중 오류가 보인 글자—
고쳤는데도 남은 오류—
제출 시도—
지금 표시된 오류—
해볼 것: ① "글자마다"로 두고 "번호를 한 자씩 적어 보기"를 누른다. 아직 적고 있는데 첫 글자부터 아홉 번째 글자까지 "자리가 모자란다"는 오류가 따라다니다가 열 번째 글자에서야 사라진다(이 장의 규칙은 옛 10자리 번호도 받는다). 대답을 시작하자마자 끼어드는 상대다. ② "칸을 떠날 때"로 바꾸고 같은 단추를 누른다. 다 적고 칸을 떠난 뒤에야 판정한다. 이름 칸을 비운 채 다음 칸으로 넘어가 보면 그때 이름 칸 아래에 오류가 뜨고, 이름을 적기 시작하면 바로 사라진다. ③ "제출할 때만"으로 바꾸고 아무것도 적지 않은 채 "신청하기"를 누른 다음, 이름을 적는다. 고쳤는데도 오류가 남아 다시 제출해야 사라진다. ④ "위 요약만"으로 바꿔 제출해 본다. 요약은 한눈에 보이지만, 칸으로 가려면 요약의 링크를 눌러야 한다. (모든 검사는 이 목업 안에서만 일어나고 아무것도 보내지 않는다. "칸을 떠날 때" 방식은 이미 오류가 보이는 칸만 글자마다 다시 검사해, 고치는 즉시 오류를 지운다.)

세 가지 시점에는 각각 자리가 있다. 글자마다 검사하면 반응은 빠르지만, 아직 다 적지 않은 값을 틀렸다고 말하게 된다. 열한 자리 번호의 첫 자리를 적는 순간 "번호가 짧다"고 하는 것은 정확하지만 쓸모없다. 다만 비밀번호 조건(여덟 자 이상, 숫자 포함)처럼 적는 동안 하나씩 채워지는 조건을 보여 줄 때는 글자마다가 맞다. 이때는 "오류"가 아니라 "진행"으로 보여 준다. 제출할 때만 검사하면 끼어들지는 않지만, 다 적은 뒤에야 한꺼번에 틀린 것을 알게 되고 고친 뒤에도 오류가 남는다. 칸을 떠날 때 검사하고, 이미 오류가 보이는 칸은 고치는 즉시 지우는 방식이 그 사이의 균형이다. "늦게 꾸짖고 빨리 칭찬한다"고 줄여 부르기도 한다. 어떤 방식이든 제출할 때 모든 칸을 한 번 더 검사하는 것은 기본이다.

인라인 검증이 오류와 작성 시간을 줄인다는 보고는 여럿 있다(예: 루크 로블레프스키, "Inline Validation in Web Forms", A List Apart, 2009에 소개된 사용성 시험). 다만 적은 수의 참가자로 한 시험이고 폼과 과제에 따라 결과가 달라질 수 있어, 숫자보다 방향을 참고하는 것이 좋다.

자리는 폼의 길이에 따라 다르게 고른다. 칸이 네댓 개인 짧은 폼은 칸 바로 아래 오류만으로 충분하다. 오류가 칸 옆에 있으니 "어느 칸"인지 따로 말할 필요가 없고, 눈이 이동할 거리도 짧다. 하지만 휴대폰에서 스크롤해야 하는 긴 폼이라면, 맨 아래 "신청하기"를 눌렀을 때 화면 밖 위쪽 칸에 생긴 오류가 보이지 않는다. 아래 시뮬레이터는 휴대폰 화면 하나 높이로 긴 폼을 보는 장면이다. 화면을 위아래로 끌어 스크롤한다.

SIMULATOR

화면 밖의 오류

화면을 위아래로 끈다
지금 화면에 보이는 오류 단서—
화면 밖에 숨은 오류—
제출 직후 사람이 아는 것—
해볼 것: ① "칸 아래만"에서 "맨 아래에서 제출 누르기"를 누른다. 화면에는 맨 아래 인원 칸의 오류만 보이고, 위쪽 휴대폰 번호 칸의 오류는 화면 밖에 있다. 사람은 인원만 고치고 다시 제출할 것이다. ② "위 요약만"으로 바꿔 다시 누른다. 이번에는 화면에 아무 변화도 보이지 않는다. 요약이 맨 위에 생겼기 때문이다. 화면을 끝까지 올려야 보인다. ③ "요약 + 칸 아래 + 요약으로 이동"으로 바꾼다. 제출하면 화면이 요약으로 올라가 오류가 두 개라는 것과 각 칸의 이름을 한 번에 알려 주고, 각 칸 아래에도 문구가 남는다. (휴대폰의 보이는 높이와 칸 높이는 이 장의 목업 값이다. 오류는 휴대폰 번호와 인원 두 칸에 있다고 정했다.)

긴 폼에서 제출이 실패하면 위 요약과 칸 아래 문구를 함께 쓰고, 화면(그리고 키보드 포커스)을 요약으로 옮기는 방식이 널리 쓰인다. 영국 정부 웹사이트의 공개 디자인 체계(GOV.UK Design System)가 이 방식을 "오류 요약" 부품으로 정리해 두었다. 요약에는 오류의 수와 각 오류로 가는 링크를 두고, 같은 문구를 해당 칸 아래에도 둔다. 요약은 "몇 개, 어디"를 한 번에 알려 주고, 칸 아래 문구는 고치는 동안 눈앞에 남는다. 짧은 폼에서는 요약 없이 칸 아래 문구만 두고, 제출에 실패하면 첫 번째 오류 칸으로 포커스를 옮긴다.

휴대폰 번호 하이픈은 넣어도 빼도 된다 010-1234-567 ! 번호가 한 자리 모자랍니다. 11자리를 적어 주세요. 인원 라벨 안내 글(라벨 아래 4) 칸 높이 44 이상 오류(칸 아래 6) 다음 칸까지 24
그림 3. 입력 칸 하나의 해부. 라벨, 안내 글, 칸, 오류 문구가 한 무리를 이루고, 다음 칸과는 그보다 넓은 간격으로 떨어진다(3장의 "안쪽 간격 < 바깥 간격"). 오류 문구는 칸에 바짝 붙어야 어느 칸의 오류인지 분명하다. 색만이 아니라 아이콘과 글자, 굵은 테두리를 함께 쓴다. 간격 숫자는 이 장의 예시값(px)이다.
오류는 화면 낭독기에게도 알려야 한다 화면에 붉은 글이 나타나도 화면 낭독기 사용자는 그것을 모를 수 있다. 칸 아래 오류 문구는 aria-describedby로 칸에 이어 칸에 들어갈 때 함께 읽히게 하고, 칸에는 aria-invalid="true"를 단다. 제출에 실패했을 때의 요약은 포커스를 요약으로 옮기거나 알림 역할(role="alert")로 읽히게 한다. WCAG 2.2의 4.1.3 상태 메시지(AA)는 포커스를 옮기지 않고 생기는 이런 알림도 보조 기술이 알 수 있어야 한다고 요구한다. 자세한 점검은 11장에서 한다.
종이 폼 대화 시험 친구나 가족 한 사람과 마주 앉는다. 내가 폼이 되고 상대가 신청자가 된다. 그림 1의 옛 폼을 종이에 그대로 옮겨 적고(칸 안에 흐린 연필로 자리표시자), 상대가 연필로 채우게 한다. 상대가 칸을 채우기 시작하면 그 칸의 연필 글씨를 지우개로 지운다. 이것이 자리표시자다. 다 채우면 3초 동안 아무 말도 하지 않다가 종이 맨 위에 "다시 확인하십시오"라고만 적는다. 이것이 맨 위 오류다. 그다음 같은 내용을 이 장의 방식(칸 위 라벨, 칸을 떠날 때 그 자리에서 말로 알려 주기)으로 다시 해 본다. 상대에게 어느 쪽이 덜 피곤했는지, 어디서 망설였는지 물어 메모한다. 연구가 아니라 간이 시험이지만, 폼을 "대화"로 볼 때 무엇이 무례한지 몸으로 알게 된다.

필수 표시와 칸 줄이기

꼭 채워야 하는 칸을 알리는 관례는 라벨 옆 별표(Asterisk, *)다. 널리 쓰여 많은 사람이 알아보지만, 별표의 뜻은 어디엔가 따로 적어 두어야 하고(그림 1처럼 맨 아래에 숨으면 소용없다), 작고 붉은 별표는 놓치기 쉽다. 그래서 요즘은 다음 두 가지 중 하나를 고르는 경우가 많다.

더 좋은 방법은 선택 칸을 없애는 것이다. 칸 하나하나는 사람의 시간과 주의를 쓴다. 칸이 왜 필요한지 설명할 수 없다면 지운다. 옛 폼의 생년월일과 주소가 그렇다. 모임 신청에 생일이나 집 주소는 필요 없다. 필요 없는 개인 정보를 모으지 않는 것은 친절이기 전에 법의 원칙이기도 하다. 개인정보 보호법(제16조)은 목적에 필요한 최소한의 개인 정보만 모으도록 정하고 있다. 모으지 않은 정보는 새어 나갈 일도 없다.

옛 폼의 칸모임 신청에 필요한가판단
이름명단과 호명에 필요둔다
휴대폰 번호확인 문자와 일정 변경 연락둔다
참가 모임무엇을 신청하는지둔다(목록 대신 고르기 단추)
인원자리 준비둔다
이메일연락은 문자로 충분지운다
생년월일쓸 데가 없다지운다
주소쓸 데가 없다지운다

칸을 지우는 것만큼 칸의 종류를 바꾸는 것도 효과가 크다. 옛 폼의 "참가 모임"은 접힌 목록(<select>)이었다. 고를 것이 두세 개뿐이라면 펼쳐 둔 고르기 단추(라디오 단추)가 낫다. 한 번에 모든 선택지가 보이고, 한 번 눌러 끝난다. 반대로 선택지가 수십 개(예: 나라 목록)라면 접힌 목록이나 검색이 낫다.

단계 나누기

칸이 많은 폼을 여러 화면으로 나누는 것을 단계형 폼(Multi-step form, 마법사)이라고 한다. 첫 화면에 칸이 서너 개만 보여 덜 부담스럽고, 단계마다 한 가지 주제(누구인지, 무엇을 신청하는지, 어떻게 연락할지)에 집중할 수 있다. 대신 화면을 넘길 때마다 기다림과 누름이 하나씩 늘고, 앞 단계로 돌아가 고치기가 번거로워지며, 전체 길이가 숨겨진다.

나눌지 말지에 대한 연구 결과는 상황마다 다르다. 그래서 아래 시뮬레이터는 실제 자료가 아니라, 판단의 구조를 보여 주려고 이 장이 정한 가상 모형이다. 칸 하나마다 일정 비율이 포기하고, 첫 화면에 칸이 많으면 시작하기 전에 떠나는 사람이 생기고, 화면을 넘길 때마다 조금 더 떠난다고 가정했다.

SIMULATOR

단계를 나누면 끝까지 가는가(가상 모형)

끝까지 가는 비율(가상)—
첫 화면의 칸—
같은 단계에서 칸을 4개로 줄이면—
해볼 것: ① 칸 7개, 단계 1에서 시작한다(옛 폼). 단계 수를 2로 올리면 첫 화면이 가벼워져 비율이 조금 오른다. 3, 4, 5로 더 올리면 화면 넘김의 비용이 쌓여 다시 내려간다. ② 칸 수를 16으로 올린다. 이번에는 단계를 3~4로 나누는 것이 가장 높다. 긴 폼일수록 나누는 이득이 크다. ③ 칸 수를 4로 내린다. 단계 1이 가장 높고, 어떤 단계 나누기보다 칸 줄이기의 효과가 크다. ④ 진행 표시를 끄면 단계마다의 이탈이 커진다. (가상 모형, 실제 수치가 아니다: 칸 하나마다 1.5%가 포기, 첫 화면에 칸이 5개를 넘으면 넘는 칸마다 3%가 시작 전에 떠남, 화면을 넘길 때마다 진행 표시가 있으면 2%, 없으면 3.5%가 떠남. 판단의 구조를 보이려고 이 장이 정한 값이다.)

모형의 숫자는 지어낸 것이지만 구조는 쓸모 있다. 첫째, 칸을 줄이는 것이 단계를 나누는 것보다 먼저다. 둘째, 단계를 나누는 이득은 칸이 많고 주제가 분명히 갈릴 때 생긴다. 셋째, 나누었다면 사람이 어디쯤 와 있는지 알려 준다. "2/3 단계"와 단계 이름을 보여 주고, 앞 단계로 돌아가도 적은 값이 사라지지 않게 한다. 마지막 단계에서는 적은 내용을 한 화면에 모아 보여 주고 고칠 수 있게 한다. 되돌릴 수 없는 결정(결제, 법적 약속)이 걸린 폼이라면 이 확인 화면이 WCAG 2.2의 3.3.4 오류 예방(AA)이 요구하는 장치이기도 하다.

단계로 나누든 한 화면에 두든 칸의 순서도 대화처럼 짠다. 쉬운 것과 무엇을 하려는지(참가할 모임)를 먼저, 개인 정보(이름, 연락처)를 그다음에 둔다. 사람들은 무엇을 얻는지 알고 나서 자기 정보를 내놓는다.

폼은 프로토타입으로 시험한다 폼의 문제는 정지 화면 시안에서는 잘 보이지 않는다. 시안에서 자리표시자는 늘 보이고, 오류는 디자이너가 그려 둔 자리에 얌전히 있다. 실제로 적어 보고, 틀려 보고, 휴대폰에서 키보드가 칸을 가리는지 봐야 문제가 드러난다. 간단한 HTML 목업이나 프로토타입 도구로 칸 네댓 개를 움직이게 만들고, 동료 몇 사람에게 "이 모임에 둘이서 신청해 보세요"처럼 과제를 주어 지켜본다. 무엇을 설명하지 말고, 어디서 손이 멈추는지만 적는다. 폼은 그 손이 멈추는 자리를 하나씩 지워 가며 완성된다.

서윤의 웹 개편 노트

CASE 서윤웹 개편 노트 · 9장

일곱 칸에서 네 칸으로

2월 둘째 주, 서윤은 모임 신청 폼에 매달렸다. 주인은 "모임 신청을 전화로 받느라 하루가 다 가요"라고 했다. 옛 사이트에도 신청 폼은 있었다. 그런데 왜 다들 전화를 할까. 서윤은 도경에게 옛 폼으로 2월 낭독 모임을 신청해 달라고 부탁하고 옆에서 지켜보았다.

도경의 휴대폰은 글자 크기가 가장 크게 설정되어 있어서, 자리표시자 "인원(본인 포함, 최대 4명)"이 "인원(본인 포…"에서 잘려 있었다. 도경은 친구 둘과 함께 갈 생각이라 "2"를 적었다가, 칸이 비면서 무엇을 적는 칸이었는지 잠깐 헷갈렸다. 휴대폰 번호는 늘 하던 대로 숫자만 적었다. 생년월일 칸에서는 "이걸 왜 물어?"라며 한참 멈췄다. "보내기"를 누르자 맨 위에 "입력 정보를 다시 확인하십시오"가 떴는데, 화면은 맨 아래에 있어서 도경은 아무 일도 일어나지 않은 줄 알았다. 두 번 더 누른 뒤 도경은 휴대폰을 내려놓고 말했다. "그냥 전화할게."

지후가 옛 폼의 코드를 열어 보니 문제가 더 보였다. 라벨 요소가 하나도 없었고, 모든 칸에 autocomplete="off"가 붙어 있었고, 번호는 하이픈이 있는 형식만 통과시켰다. "번호 형식은 제가 정리할게요. 사람이 하이픈을 맞출 이유가 없어요." 서윤은 이 장의 시뮬레이터로 세 가지를 비교한 뒤 다음처럼 정했다.

항목옛 폼서윤의 선택
칸7개(이름, 이메일, 휴대폰 번호, 생년월일, 주소, 참가 모임, 인원)4개: 참가 모임 → 이름 → 휴대폰 번호 → 인원
라벨자리표시자만칸 위 라벨(14px, 굵게), 안내 글은 라벨 아래 13px, 자리표시자는 쓰지 않음
간격·크기제각각라벨–칸 8px, 칸 높이 48px(7장의 터치 타깃 44px 이상), 칸 사이 24px, 입력 글자 17px
참가 모임접힌 목록펼친 고르기 단추 2개(한 줄 높이 44px 이상)
휴대폰 번호010-0000-0000만type="tel", autocomplete="tel", 어떤 모양이든 숫자만 뽑아 010-0000-0000으로 저장
인원칸 하나, 안내는 자리표시자inputmode="numeric", 칸 폭 110px, 라벨 아래 "본인 포함, 1~4명"
검증 시점제출할 때만칸을 떠날 때. 오류가 보이는 칸은 고치는 즉시 지움. 제출 때 전체 재검사 후 첫 오류 칸으로 포커스
오류 자리와 모양맨 위 한 줄칸 바로 아래(4px), 위험 색 #c53732(흰 바탕 대비 5.29) + 느낌표 아이콘 + 고칠 방법을 말하는 문구, 칸 테두리 2px
필수 표시맨 아래 별표 설명네 칸 모두 필수라 별표 없이 폼 위에 "네 칸 모두 적어 주세요" 한 줄
단계한 화면한 화면 유지(칸 4개라 나누지 않음)

서윤은 처음에 오류 요약도 위에 두려 했다. 지후가 "네 칸짜리 폼이면 휴대폰에서도 한 화면에 거의 다 들어와요. 요약은 긴 폼에서 쓰고, 여기선 첫 오류 칸으로 포커스만 옮기죠"라고 해서 칸 아래 문구만 남겼다. 이메일 칸을 지울 때는 주인이 망설였다. 소식지를 보내고 싶다는 것이었다. 서윤은 신청 폼과 소식지 구독을 나누자고 했다. 소식지는 신청이 끝난 화면에서 "소식지도 받으시겠어요?"라고 따로 묻기로 했다. 신청하러 온 사람에게 신청에 필요한 것만 묻는다는 원칙이다.

새 시안으로 도경이 다시 신청했다. 고르기 단추 하나를 누르고, 이름은 휴대폰이 제안한 것을 한 번 눌러 넣었다. 번호에서 일부러 한 자리를 빼 보라고 하자, 다음 칸으로 넘어가는 순간 칸 바로 아래에 "번호가 한 자리 모자랍니다"가 떴고, 한 자리를 더하자 바로 사라졌다. 도경은 "이건 전화보다 빠르네"라고 했다.

이 장에서 정한 것칸 위 라벨(자리표시자 없음), 칸을 떠날 때 검증하고 고치는 즉시 오류 해제, 오류는 칸 바로 아래에 위험 색 #c53732·아이콘·문구로, 칸 수 7 → 4(참가 모임, 이름, 휴대폰 번호, 인원). 번호는 어떤 모양이든 받아 정리해 저장한다. 칸 높이 48px, 칸 사이 24px, 입력 글자 17px. 단계는 나누지 않는다.
아직 남은 문제지후가 "신청하기"를 누르면 폼이 접히고 완료 카드가 튀어 오르는 애니메이션을 넣고 싶어 한다. 메뉴와 신간 카드에도 이미 움직임을 잔뜩 넣어 두었다. 화면 낭독기로 오류를 알 수 있는지는 아직 확인하지 않았다.
다음 단계10장: 지후의 애니메이션을 도경과 함께 본다.

핵심 정리

  1. 폼은 사람과 화면의 짧은 대화다. 무엇을 묻는지 분명히 말하고, 대답하는 동안 끼어들지 않고, 틀리면 그 자리에서 고칠 방법을 알려 주고, 필요 없는 것을 묻지 않는다.
  2. 자리표시자는 라벨이 아니다. 적는 순간 사라져 기억에 기대게 하고, 흐린 색이라 대비가 낮으며, 다 채운 뒤에는 칸의 이름을 잃는다. 라벨은 칸 위에, 안내 글은 라벨 아래에 둔다.
  3. 칸의 폭과 높이는 기대하는 답의 길이를 알려 준다. 넓은 화면에서는 짧은 칸을 짧게 두고, 좁은 화면에서는 대부분 화면 폭에 맞춘다.
  4. type·inputmode는 알맞은 키보드를, autocomplete는 저장된 정보의 제안을 부른다(WCAG 1.3.5). 숫자로 된 글자에는 type="number" 대신 inputmode="numeric"을 쓴다. 입력 글자는 16px 이상.
  5. 형식은 기계가 맞춘다. 여러 모양의 입력을 받아 한 형식으로 정리하고, 오류 문구는 어느 칸·무엇이 문제·어떻게 고치는지를 말한다(WCAG 3.3.1, 3.3.3). 색만으로 알리지 않는다.
  6. 칸을 떠날 때 검증하고 고치는 즉시 오류를 지우는 방식이 균형점이다. 짧은 폼은 칸 아래 문구만, 스크롤이 필요한 긴 폼은 위 요약과 칸 아래 문구를 함께 쓰고 요약으로 이동한다.
  7. 필수 칸이 대부분이면 선택 칸에만 "(선택)"을 붙인다. 더 좋은 것은 필요 없는 칸을 지우는 것이다. 단계 나누기는 칸을 줄인 다음, 칸이 많고 주제가 갈릴 때 진행 표시와 함께 쓴다.

확인 퀴즈

1. 라벨 없이 칸 안의 자리표시자에 "인원(본인 포함, 최대 4명)"이라고만 적어 둔 폼의 문제로 가장 알맞은 것은?

자리표시자는 입력을 시작하면 사라지므로 기억, 대비, 검토에서 모두 손해를 본다. 진하게 칠하면 이미 채운 칸처럼 보이는 새 문제가 생긴다. 화면 낭독기가 자리표시자를 읽는 경우도 있지만 값을 적은 뒤에는 사라지고, 문제는 시각 장애인에게만 있는 것이 아니다. 자리표시자는 오히려 세로 공간을 가장 적게 쓴다.

2. 휴대폰에서 6자리 인증번호를 받는 칸을 만든다. 가장 알맞은 설정은?

인증번호는 수량이 아니라 숫자로 된 글자라 type="number"(앞자리 0 삭제, 휠로 값 변경 등)보다 inputmode="numeric"이 안전하다. one-time-code는 문자로 받은 번호를 제안하게 해 입력을 한 번으로 줄인다. autocomplete="off"는 이 도움을 막고, 이메일 형식은 엉뚱한 키보드를 부른다.

3. 사람이 휴대폰 번호 칸에 첫 숫자 "0"을 적자마자 "번호가 너무 짧습니다"라는 오류가 떴다. 어떤 검증 방식 때문이고, 무엇으로 바꾸는 것이 좋은가?

아직 다 적지 않은 값을 틀렸다고 말하는 것은 글자마다 검사할 때 생기는 "이른 경고"다. 칸을 떠날 때 검사하면 다 적은 뒤에 판정하고, 이미 보이는 오류는 고치는 즉시 지워 늦은 해제 문제도 피한다. 오류의 자리(요약, 칸 아래)는 시점과 다른 결정이다.

4. 칸이 열두 개인 긴 폼을 휴대폰에서 끝까지 내려와 "제출"을 눌렀는데, 오류가 맨 위쪽 칸 두 개에 있다. 가장 알맞은 처리는?

화면이 맨 아래에 있으면 위쪽 칸의 문구도, 맨 위의 한 줄도 보이지 않는다. 긴 폼에서는 요약(몇 개, 어디)과 칸 아래 문구(고치는 동안 눈앞에)를 함께 쓰고 요약으로 이동하는 방식이 널리 쓰인다. 색만으로 알리는 것은 무엇이 왜 틀렸는지 말하지 않고, 색각에 따라 보이지 않을 수도 있다.