10.1 자동완성, 켜두면 뭐가 좋아요?
주소를 입력하는 폼을 떠올려 볼게요. 스마트폰에서 이름, 전화번호, 주소를 하나하나 손가락으로 치는 건 은근히 고역이에요. 그런데 브라우저는 사용자가 예전에 저장해둔 정보를 알고 있어요. 우리가 폼에 autocomplete(오토컴플리트, 자동완성) 속성을 제대로 달아주면, 브라우저가 "이 칸은 전화번호구나" 하고 알아채서 저장된 값을 한 번의 탭으로 채워줘요.
자동완성은 단순히 편한 정도가 아니에요. 입력이 빨라지면 폼을 끝까지 채우는 사람이 늘어요. 오타도 줄고요. 특히 결제나 주소 폼처럼 칸이 많은 화면에서 이 차이가 크게 벌어져요. 오늘은 이 자동완성과, 누구나 폼을 쓸 수 있게 하는 접근성(accessibility, 접근성)까지 함께 다뤄볼게요.
10.2 autocomplete는 어떻게 켜죠?
비결은 input마다 어떤 정보인지 알려주는 이름표를 붙이는 거예요. 이 이름표를 토큰(token, 정해진 값 이름)이라고 불러요. 아무 단어나 쓰는 게 아니라 정해진 목록에서 골라 써야 브라우저가 알아들어요.
<input name="fname" autocomplete="name">
<input name="mail" type="email" autocomplete="email">
<input name="phone" type="tel" autocomplete="tel">
<input name="zip" autocomplete="postal-code">
자주 쓰는 토큰은 이래요. 이름은 name, 이메일은 email, 전화번호는 tel, 우편번호는 postal-code, 주소는 street-address예요. 비밀번호 칸에도 토큰이 있어요. 로그인 칸은 current-password, 회원가입에서 새로 정하는 칸은 new-password라고 적어요. 이 둘을 구분해두면 브라우저가 새 비밀번호를 만들 때 저장된 옛 비밀번호를 잘못 넣는 실수를 안 해요.
동작을 볼게요. tel 토큰이 붙은 칸을 누르면 스마트폰 키보드 위에 저장해둔 전화번호가 추천으로 뜨고, 그걸 누르면 값이 바로 들어가요. 반대로 토큰을 안 붙이거나 엉뚱하게 붙이면 이 추천이 아예 안 뜨거나 이상한 값이 채워져요.
반대로 자동완성을 끄고 싶은 칸도 있어요. 문자로 받은 일회용 인증번호처럼 매번 새로 입력하는 값은 저장돼봤자 방해만 되죠. 이럴 땐 autocomplete="off"로 꺼줘요. 다만 이름이나 주소 같은 재사용되는 값은 절대 끄지 마세요. 사용자 편의를 오히려 해치거든요. 끄는 건 정말 매번 달라지는 값에만 쓰는 거예요.
10.3 label은 왜 꼭 필요해요?
입력칸 옆에 그냥 글자로 "이메일"이라고 써두면 될 것 같지만, 그건 label(레이블, 입력칸 이름표) 태그로 묶어야 제값을 해요. label을 쓰면 두 가지가 좋아져요. 첫째, 글자를 눌러도 연결된 칸에 커서가 들어가요. 체크박스처럼 작은 칸은 이게 특히 편하죠. 둘째, 스크린 리더(screen reader, 화면을 읽어주는 보조 프로그램)가 "이 칸은 이메일 칸입니다" 하고 읽어줘요.
연결하는 방법은 두 가지예요. label의 for 값과 input의 id를 같은 이름으로 맞추거나, 아예 input을 label 안에 넣어버리는 거예요.
<label for="email">이메일</label>
<input id="email" type="email">
<label>이메일 <input type="email"></label>
둘 다 결과는 같아요. for와 id를 맞추는 방식이 이름표와 칸을 떨어뜨려 배치할 때 자유로워서 실무에서 더 많이 쓰여요. 참고로 placeholder(칸 안에 흐리게 뜨는 예시 글씨)로 이름표를 대신하면 안 돼요. 값을 입력하는 순간 사라져서 무슨 칸이었는지 알 수 없거든요.
10.4 라디오 버튼 묶음엔 뭘 써요?
"성별"이나 "배송 방법"처럼 여러 선택지가 한 질문에 묶이는 경우가 있어요. 라디오 버튼 여러 개가 하나의 질문이라는 걸 알려주려면 fieldset(필드셋, 입력 묶음)으로 감싸고 그 제목을 legend(레전드, 묶음 제목)로 달아요.
<fieldset>
<legend>배송 방법</legend>
<label><input type="radio" name="ship" value="fast"> 빠른배송</label>
<label><input type="radio" name="ship" value="normal"> 일반배송</label>
</fieldset>
스크린 리더는 이 묶음을 읽을 때 "배송 방법, 빠른배송" 하는 식으로 제목을 함께 읽어줘요. legend가 없으면 그냥 "빠른배송"만 들려서, 무엇에 대한 선택인지 알 수가 없죠. 눈으로 보는 사람에게도 fieldset은 테두리로 묶어줘서 관련 있는 항목이라는 게 한눈에 보여요.
10.5 스크린 리더에 상태는 어떻게 알려요?
label만으로 부족한 정보는 aria(에이리아, 접근성 보조 속성)로 채워요. 몇 가지만 알아도 충분해요. 필수 입력이면 aria-required="true", 검증에 실패한 칸이면 aria-invalid="true"를 붙여요. 그러면 스크린 리더가 "필수, 입력 오류" 같은 상태까지 함께 읽어줘요.
<label for="pw">비밀번호</label>
<input id="pw" type="password" aria-required="true" aria-describedby="pwhint">
<p id="pwhint">8자 이상 입력하세요</p>
aria-describedby는 그 칸에 대한 설명 문구를 연결하는 속성이에요. 값으로 설명 문단의 id를 적어주면, 칸에 커서가 갔을 때 스크린 리더가 "비밀번호, 8자 이상 입력하세요"까지 읽어줘요. 눈에 보이는 안내 문구를 소리로도 그대로 전달하는 거죠. aria는 label로 안 되는 부분을 보충하는 용도라, label을 먼저 제대로 달고 그 위에 얹는다고 생각하면 돼요.
한 가지 자주 하는 실수를 짚고 갈게요. label이 이미 있는 칸에 aria-label까지 또 붙이는 경우예요. aria-label은 화면에 안 보이는 이름을 붙이는 속성인데, label이 있으면 이게 label을 덮어써버려서 둘이 어긋날 수 있어요. label로 이름이 이미 붙은 칸엔 aria-label을 중복해서 달지 않는 게 원칙이에요. 눈에 보이는 이름표가 있으면 그걸 쓰고, 아이콘 버튼처럼 보이는 글자가 아예 없을 때만 aria-label로 이름을 붙여주면 돼요.
10.6 오늘 배운 걸 정리해볼게요
오늘은 폼을 빠르고 누구나 쓸 수 있게 만드는 두 축을 봤어요. 하나는 autocomplete 토큰이에요. name, email, tel, postal-code 같은 정해진 이름표를 붙이면 브라우저가 저장값을 한 번에 채워줬죠. 비밀번호는 current-password와 new-password를 구분하는 게 요령이었고요.
다른 하나는 접근성이에요. 모든 입력엔 label을 for·id로 연결하고, 선택지 묶음은 fieldset과 legend로 감싸고, 부족한 상태는 aria-required나 aria-describedby로 채웠어요. 여러분의 폼에 label부터 하나씩 달아보세요. 마우스 대신 글자를 눌러 커서가 들어가는 걸 확인하면, 접근성이 특별한 게 아니라 기본을 지키는 일이라는 걸 알게 될 거예요.