Skip to content
This page has been auto-translated and may contain errors.View in English

양식 및 입력

docs.scrimba.com

검색창, 로그인, 결제, 댓글 입력 같이 어떤 작업을 하는 거의 모든 웹사이트는 양식으로 구축됩니다. 양식은 페이지가 방문자에게 일방적으로 보여주는 것에서 벗어나 정보를 청취하기 시작하는 방식입니다. 양식은 누군가가 입력하고, 선택하고, 선택한 내용을 수집한 뒤 처리될 수 있도록 전달합니다. 이 장에서는 이를 가능하게 하는 HTML에 대해 다룹니다.

form 요소

**양식**은 방문자가 입력하는 것들을 함께 묶는 컨테이너입니다. 입력 항목과 버튼을 <form> 요소 안에 넣으면, 양식의 역할은 모든 것을 모아서 방문자가 완료했을 때 전송하는 것입니다.

html
<form>
  <label>이름</label>
  <input>
  <button>전송</button>
</form>

병원에서 받는 종이 양식처럼 생각해보세요. 시트가 모든 상자를 포함하고, 각 상자에 작성한 후 맨 아래에서 전체 시트를 한 번에 제출합니다. <form> 요소가 바로 그 시트입니다.

<form>은 컨트롤을 수집하여 하나의 묶음으로 제출하는 컨테이너입니다. 두 개의 속성이 제출 시 일어나는 일을 결정합니다. action은 데이터가 전송되는 주소이고, method는 전송하는 방식입니다.

html
<form action="/subscribe" method="post">
  <label for="email">이메일 주소</label>
  <input id="email" name="email" type="email">
  <button type="submit">구독</button>
</form>

방문자가 제출을 트리거하면, 브라우저는 양식 내의 모든 명명된 컨트롤을 수집하고, 값들을 패키징한 후 action 주소로 요청을 전송합니다. 이 모든 작업을 직접 연결할 필요가 없습니다. <form> 요소가 이 동작을 자동으로 제공하므로, 느슨한 입력을 페이지에 흩어 놓는 것보다 실제 양식에 컨트롤을 그룹화하는 것이 훨씬 낫습니다.

<form>은 기본 제출 메커니즘입니다. 스크립트 없이 양식의 컨트롤을 요청으로 모아서 전송하는 기본 제공 브라우저 동작입니다. 제출할 때 브라우저는 action(요청이 가는 URL)과 method(get 또는 post, 이 장의 뒷부분에서 다룸)을 읽고, 컨트롤을 요청으로 직렬화하며, 탐색합니다. 이 기본 동작이 JavaScript가 비활성화되거나 아직 로드되지 않은 경우에도 양식이 작동하는 이유입니다. 이것은 당신이 대체하는 것이 아니라 위에서 구축하는 기초입니다.

html
<form action="/subscribe" method="post">
  <label for="email">이메일 주소</label>
  <input id="email" name="email" type="email">
  <button type="submit">구독</button>
</form>

두 가지 동작이 사람들을 헷갈리게 합니다. 첫째, 양식은 단일 행 텍스트 필드에서 포커스가 있을 때 Enter 키로 제출되며, 버튼 클릭만으로는 제출되지 않습니다. 따라서 키보드 제출이 기본으로 제공되며 테스트할 가치가 있습니다. 둘째, 기본 제출은 페이지를 새로고침하거나 탐색합니다. JavaScript로 양식을 처리할 때 event.preventDefault()를 호출하여 해당 탐색을 중지하고 직접 처리합니다. 기본 제출을 기초로 생각하세요. 스크립트가 실행되기 전에도 합리적인 작업을 수행해야 합니다. 점진적 개선, 작동하는 HTML 위에 스크립트를 계층화하는 방식이 여기서 시작하는 이유입니다.

Junoform 요소<form>은 입력 항목과 버튼을 포함하는 컨테이너이며, 누군가가 제출할 때 모든 것을 함께 전송합니다. 책상의 종이 양식을 생각해보세요. 하나의 시트, 많은 상자, 한 번에 제출됩니다. 필드를 양식으로 감싸면 특별한 작업 없이 수집 및 전송 동작을 얻습니다.
Junoform 요소<form>은 컨트롤을 묶어서 제출합니다. action은 어디로 제출할지, method는 어떻게 제출할지를 지정합니다. 수집 및 전송 기능을 무료로 얻을 수 있으므로, 느슨한 입력과 자신의 클릭 핸들러 대신 실제 양식을 사용하세요. 코드를 절약하고 스크립트가 로드되기 전에도 작동합니다.
Junoform 요소 기본 제출은 스크립트 없이 컨트롤을 수집하여 action으로 요청을 전송합니다. 이것이 바로 JavaScript가 꺼져 있을 때도 양식이 작동하는 이유입니다. 텍스트 필드에서 Enter 키로 제출되며 클릭만으로는 제출되지 않음을 기억하세요. JavaScript로 직접 처리할 때 event.preventDefault()는 기본 탐색을 중지하고, 기초가 되는 일반 양식은 여전히 안전장치로 작동합니다.

입력 및 레이블

<input>은 방문자가 입력하는 상자입니다. 하지만 혼자서는 <input>이 무엇을 하는 상자인지 알 수 없는 빈 상자입니다. 그것이 **레이블**의 역할입니다. 방문자에게 상자에 무엇을 입력할지 알려주는 텍스트입니다.

html
<label for="city">도시</label>
<input id="city">

모든 입력에는 레이블이 필요합니다. 입력에 id를 부여하고 레이블에서 for로 가리키되, 둘 다 같은 단어를 사용하여 두 요소를 연결합니다. 연결되면 레이블을 클릭하면 커서가 상자에 표시되는데, 이는 모든 사람에게 양식을 더 쉽게 사용할 수 있게 해주는 작은 배려입니다.

<input>은 단일 값을 수집하고, <label>은 이름을 붙입니다. 레이블의 for 속성을 입력의 id와 일치시켜 연결합니다.

html
<label for="username">사용자명</label>
<input id="username" name="username" type="text" required>

몇 가지 속성이 대부분의 입력에서 유용합니다. name은 값이 전송되는 키입니다(명명 섹션에서 다룸). required는 필드를 채울 때까지 제출을 차단합니다. placeholder는 상자 내에 희미한 힌트 텍스트를 보여주지만, placeholder는 레이블이 아닙니다. 누군가 입력하는 순간 사라지므로 실제 레이블을 대체할 수 없습니다. 모든 입력에는 여전히 자신의 <label>이 필요합니다.

<label>을 컨트롤과 연결하는 두 가지 방법이 있으며, 접근성에서 그 차이가 중요합니다. 첫 번째는 명시적 연결입니다. 레이블이 컨트롤의 id와 같은 값을 가진 for 속성을 포함합니다. 두 번째는 암시적 연결입니다. 컨트롤을 레이블 요소 내에 감싸고 forid는 필요하지 않습니다.

html
<!-- 명시적: for이 id와 일치 -->
<label for="phone">전화</label>
<input id="phone" name="phone" type="tel">

<!-- 암시적: input이 label 내부에 있음 -->
<label>
  전화
  <input name="phone" type="tel">
</label>

둘 다 컨트롤에 **접근 가능한 이름**을 제공합니다. 필드에 포커스가 올 때 스크린 리더가 알려주는 텍스트입니다. 따라서 레이아웃을 볼 수 없는 방문자도 무엇을 입력할지 알 수 있습니다. 명시적 연결을 선호하세요. CSS 레이아웃에서 레이블이 입력에서 움직이거나, 스타일링이 둘을 분리할 때도 작동합니다. 연결된 레이블이 없는 필드는 목적이 없는 편집 상자로 알려지며, 이는 웹에서 가장 일반적인 접근성 오류 중 하나입니다. 접근성 장에서 더 자세히 다룹니다.

Juno입력 및 레이블<input>은 사람들이 입력하는 상자이고, <label>은 그곳에 무엇이 들어가는지 알려주는 텍스트입니다. 일치하는 forid로 연결하면 레이블을 클릭하면 바로 상자로 이동합니다. 모든 단일 입력에 레이블을 붙이세요. 옆에 단어가 없는 외로운 상자는 사람들만 헷갈리게 합니다.
Juno입력 및 레이블 레이블의 for를 입력의 id와 일치시키면 둘이 연결됩니다. required를 활용하여 빈 제출을 차단하지만, placeholder가 레이블을 대체하도록 하지 마세요. 누군가 입력하는 순간 사라집니다. 실제 레이블, 모든 필드, 예외 없음.
Juno입력 및 레이블 레이블을 연결하는 두 가지 방법: forid와 일치하거나 input을 레이블 내부에 감싸기. 둘 다 필드에 접근 가능한 이름을 제공하며, 명시적 for/id는 CSS가 떨어뜨릴 때 더 튼튼한 선택입니다. 레이블이 없는 필드는 이름 없는 상자로 읽혀지는데, 이는 현재 가장 흔한 접근성 누락 중 하나입니다.

기타 컨트롤

모든 것이 일반 텍스트 상자는 아닙니다. 어떤 질문은 선택, 체크 또는 목록에서 선택하는 방식이 더 나을 수 있습니다. 체크박스는 온-오프 토글이며, 드롭다운은 여러 옵션 중 하나를 선택할 수 있게 합니다.

html
<label>
  <input type="checkbox"> 뉴스레터 보내주세요
</label>

<label for="size">크기</label>
<select id="size">
  <option>작음</option>
  <option>중간</option>
  <option>큼</option>
</select>

이것을 외울 필요는 없습니다. 지금 핵심은 양식이 적합한 어떤 방식으로든 질문을 할 수 있다는 것입니다. 입력, 체크, 또는 목록에서 선택.

<input> 요소는 type 속성에 따라 모양이 변하며, 올바른 type은 더 나은 키보드, 기본 제공 검증, 기본 선택기를 무료로 제공합니다.

html
<input type="email">     <!-- @ 형태를 검증하고, 모바일에서 이메일 키보드 -->
<input type="number">    <!-- 숫자 키패드, 위/아래 스테퍼 -->
<input type="password">  <!-- 문자를 마스킹함 -->
<input type="date">      <!-- 기본 날짜 선택기 -->
<input type="checkbox">  <!-- 단일 온/오프 토글 -->
<input type="radio">     <!-- 그룹에서 하나 선택 -->

<input> 외에도 세 가지 요소가 나머지를 다룹니다. <textarea>는 더 긴 글쓰기를 위한 여러 줄의 텍스트 상자입니다. <select><option> 자식이 있으면 드롭다운 목록입니다. 관련 필드를 시각적으로 그리고 의미적으로 그룹화해야 할 때, <fieldset>으로 감싸고 그룹의 이름을 지정하는 <legend>를 포함하세요.

html
<fieldset>
  <legend>배송 속도</legend>
  <label><input type="radio" name="speed" value="standard"> 표준</label>
  <label><input type="radio" name="speed" value="express"> 특급</label>
</fieldset>

<label for="message">메시지</label>
<textarea id="message" name="message" rows="4"></textarea>

버튼도 type을 가집니다. type="submit"은 양식을 전송하며(양식 내 버튼의 기본값), type="reset"은 모든 필드를 초기값으로 지웁니다. type="button"은 자체적으로는 아무 것도 하지 않으며 JavaScript가 연결하기 위해 사용됩니다.

각 컨트롤 type은 배포하기 전에 알아야 할 동작을 가집니다. 라디오 버튼은 공유하는 name으로 그룹화됩니다. 그룹의 라디오 버튼 중 하나만 한 번에 선택될 수 있으며, 상호 배타성을 만드는 것이 바로 이 그룹화입니다. 따라서 누락된 또는 일치하지 않는 name은 조용히 그룹을 독립적인 토글로 분해합니다.

html
<fieldset>
  <legend>배송 속도</legend>
  <label><input type="radio" name="speed" value="standard" checked> 표준</label>
  <label><input type="radio" name="speed" value="express"> 특급</label>
</fieldset>

<fieldset><legend>는 시각적인 것만이 아닙니다. <legend>는 스크린 리더에 의해 세트의 모든 컨트롤에 대한 컨텍스트로 알려집니다. 따라서 "배송 속도" fieldset 내의 라디오는 "배송 속도, 표준"으로 읽혀지며, 이것이 이해할 수 있는 양식과 떠 있는 옵션 목록의 차이입니다. 두 가지 추가 주의사항이 있습니다. 체크박스는 선택되었을 때만 값을 전송합니다. 선택되지 않은 상자는 제출에서 완전히 제외되므로 서버는 false가 아닌 아무 것도 보지 않습니다. 이것이 다른 쪽에서 데이터를 읽는 방식을 형성합니다. 그리고 type="submit"은 양식 내 <button>의 기본 type이므로, JavaScript 트리거로 의도한 일반 <button>type="button"을 설정하지 않으면 양식을 제출하고 페이지를 새로고침합니다. 이 기본값이 계속 사람들을 잠깐 멈추게 합니다.

Juno기타 컨트롤 양식은 한 가지 이상의 방식으로 질문할 수 있습니다. 예/아니오는 체크박스, 목록에서 한 가지를 선택하는 것은 드롭다운. 체크박스는 <input type="checkbox">이고, 드롭다운은 <option> 선택을 포함하는 <select>입니다. 외울 필요가 없습니다. 질문이 필요할 때 양식에는 일반 상자 이상이 있습니다.
Juno기타 컨트롤 input의 type은 그것을 다시 형성합니다. email, number, date, password, checkbox, radio, 각각 어울리는 키보드 또는 선택기가 있습니다. 긴 텍스트를 위해 <textarea>를 사용하세요. 드롭다운을 위해 <select>를, 관련 필드를 그룹화할 때 <legend>가 있는 <fieldset>을 사용하세요. 버튼 type을 확인하세요. submit이 양식 내의 기본값입니다.
Juno기타 컨트롤 라디오는 공유 name으로 그룹화되며, <legend>는 fieldset의 모든 컨트롤에 음성 컨텍스트를 제공합니다. 따라서 장식이 아닌 구조입니다. 두 가지 함정이 있습니다. 선택되지 않은 체크박스는 false가 아닌 전혀 아무 것도 전송하지 않으며, 일반 <button>type="button"으로 설정하지 않으면 기본으로 type="submit"이 되어 페이지를 새로고침합니다.

양식 데이터가 명명되고 제출되는 방식

양식이 전송될 때, 각 답변에는 누가 받든 어느 상자에서 왔는지 알 수 있도록 레이블이 필요합니다. 그 레이블이 입력의 name입니다. 한 번 설정하면 값과 함께 전달됩니다.

html
<label for="city">도시</label>
<input id="city" name="city">

방문자가 그 상자에 "서울"을 입력하면, 양식은 "city는 서울"이라는 쌍을 전송합니다. name은 수신 측이 한 답변을 다른 것과 구분하는 방법입니다. name이 없는 입력은 제출에서 완전히 제외되므로, 이 작은 속성이 실제로 데이터가 표시되도록 하는 것입니다.

양식 데이터는 **이름/값 쌍**의 집합으로 전송됩니다. 각 컨트롤의 name이 키가 되고 방문자가 입력한 것이 값이 됩니다. name이 있는 컨트롤만 포함되므로, name은 컨트롤을 제출 데이터로 변환하는 것입니다.

html
<form action="/search" method="get">
  <label for="q">검색</label>
  <input id="q" name="q" type="search">
  <label for="sort">정렬 기준</label>
  <select id="sort" name="sort">
    <option value="recent">최신순</option>
    <option value="top">상위 평점순</option>
  </select>
  <button type="submit">검색</button>
</form>

method 속성은 이러한 쌍이 이동하는 방식을 결정합니다. method="get"은 쿼리 문자열로 URL에 추가합니다(/search?q=부츠&sort=recent). 이는 북마크하거나 공유할 수 있는 검색과 필터에 적합합니다. method="post"는 URL에서 보이지 않게 요청 본문에 넣습니다. 이는 비밀번호나 결제처럼 데이터를 변경하거나 URL에 표시되지 않아야 하는 모든 것에 적합합니다.

모든 제출은 이름/값 쌍의 집합이며, 세 가지 세부사항이 인코딩 및 전송 방식을 결정합니다.

첫 번째는 method입니다. get은 쌍을 URL의 쿼리 문자열로 직렬화합니다. 주소 뒤의 ?key=value&key=value 텍스트입니다. 이것은 요청을 반복 가능하고 북마크 가능하게 만들며, 값이 URL, 브라우저 기록, 서버 로그에 표시되므로, get은 읽기(검색, 필터)에만 사용되고 절대 비밀에는 사용되지 않습니다. post는 URL을 벗어나 요청 본문에 쌍을 전달하며, 이는 상태를 변경하거나 민감한 것들의 선택입니다.

두 번째는 enctype입니다. 본문의 형식을 지정하는 인코딩입니다. 기본값인 application/x-www-form-urlencoded는 쌍을 하나의 key=value&... 문자열로 압축하며, 이는 텍스트에는 좋습니다. 선택한 파일을 전송하려면 enctype="multipart/form-data"로 전환해야 합니다. 이는 텍스트 필드와 함께 파일 바이트를 전달할 수 있는 형식입니다. 파일 입력은 이 없이 올바르게 업로드되지 않습니다.

html
<form action="/upload" method="post" enctype="multipart/form-data">
  <label for="avatar">프로필 사진</label>
  <input id="avatar" name="avatar" type="file">
  <button type="submit">업로드</button>
</form>

세 번째는 autocomplete이며, UX와 접근성에서 명명이 보상을 받는 곳입니다. autocomplete 토큰은 브라우저에 표준 용어로 필드의 의미를 알려주므로 올바른 저장된 값을 제안할 수 있습니다. autocomplete="email", autocomplete="name", autocomplete="current-password", autocomplete="street-address". 이 토큰은 자유 텍스트가 아닌 고정 어휘이며, 올바르게 설정하면 브라우저 또는 비밀번호 관리자가 한 번의 탭으로 양식을 채울 수 있습니다. 이는 휴대폰에서 입력하거나 보조 기술을 사용하는 사람들에게 가장 중요합니다.

html
<label for="email">이메일</label>
<input id="email" name="email" type="email" autocomplete="email">

기본 제공 검사를 정직하게 유지하는 것은 별도의 작업이며, 양식 검증 장에서 다룹니다. 이 섹션은 데이터가 유효해지면 어떻게 형성되고 전송되는지입니다.

Juno양식 데이터가 명명되고 제출되는 방식 각 입력의 name은 답변의 태그이므로, 수신자는 값이 도시 상자에서 왔는지 이메일 상자에서 왔는지 알 수 있습니다. name을 설정하면, 상자의 값이 레이블이 붙은 쌍으로 전송됩니다. 잊으면, 그 필드는 조용히 제외되며, 많은 사람들이 양식이 아무것도 반환하지 않을 때 처음 실수합니다.
Juno양식 데이터가 명명되고 제출되는 방식 제출된 데이터는 이름/값 쌍이며, name이 있는 컨트롤만 포함됩니다. 업무에 맞게 method를 선택하세요. get은 값을 북마크하거나 공유할 수 있는 검색과 필터를 위해 URL에 넣습니다. post는 데이터를 변경하거나 비밀을 보유하는 모든 것을 위해 본문에 숨깁니다. URL에 비밀번호를 넣는 것이 절대 만들면 안 되는 실수입니다.
Juno양식 데이터가 명명되고 제출되는 방식get은 쌍을 URL에 쓰므로 읽기용이고 비밀에는 절대 사용되지 않습니다. post는 본문에 전달합니다. 파일 입력이 업로드되지 않으면 enctypemultipart/form-data로 전환하세요. 그리고 emailcurrent-password 같은 autocomplete 토큰에 노력을 기울이세요. 이것은 고정 어휘이며, 올바르게 설정하면 휴대폰이나 비밀번호 관리자가 한 번의 탭으로 양식을 채울 수 있습니다.