폼(form)은 입력 칸과 단추를 묶는 요소입니다. 단추를 누르면 브라우저가 칸에 친 값을 모아 주소 뒤에 붙이고 그 주소로 떠납니다. 이 일을 제출(submit)이라고 합니다.
지금까지 만든 페이지는 읽기만 하는 페이지였습니다. 레시피 노트에 후기를 남기거나 레시피를 찾게 하려면, 페이지를 보는 사람이 친 글을 들고 갈 길이 있어야 합니다. 그 길이 폼입니다.
이 레슨에서는 단추를 누른 순간 브라우저가 하는 세 가지 일(모으기 · 붙이기 · 떠나기)과 값을 들고 갈 곳을 정하는 action을 봅니다.
이 단원을 마치면 김치볶음밥 페이지에 이름 · 별점 · 한 줄 평 · 다시 만들 의향을 받는 후기 남기기 폼을 만들 수 있습니다.
이 단원(폼)을 이미 안다면 단원 연습 문제부터 풀고 틀린 레슨만 보세요. 건너뛸지 볼 때는 힌트를 펴지 않고 풉니다.
1폼은 칸과 단추를 묶는다
<form>
<label for="nick">이름</label>
<input
id="nick"
name="nickname"
/>
<button type="submit">
후기 남기기
</button>
</form>결과 화면은 칸에 글을 치고 단추를 눌러도 떠나지 않습니다. 결과 화면 머리의 '눌러도 떠나지 않음'이 그 표시입니다. 보내면 무엇이 일어나는지는 위 흐름 그림과 내 파일에서 봅니다.
form 요소 안에 칸과 단추를 넣습니다.
input은 한 줄 글을 치는 글자 칸입니다. 내용이 없는 빈 요소라 닫는 태그 없이/>로 끝냅니다. 속성이 길어 한 줄에 하나씩 나눠 적었습니다.label은 칸 앞에 붙는 이름 글자입니다.for와 칸의id를 같게 적어 짝을 짓습니다 — 셋째 레슨 label로 칸에 이름 붙이기에서 자세히 봅니다.name은 값을 보낼 때 붙이는 이름입니다 — 다음 레슨 name과 value에서 봅니다.- 단추의
type="submit"은 '이 단추는 폼을 보낸다'는 뜻입니다.
폼 안의 단추는 type을 적지 않아도 누르면 폼을 보냅니다. 보내지 않을 단추까지 페이지를 새로 불러오는 까닭과 막는 법은 이 단원 끝 레슨 단추의 type에서 봅니다.
2누르면 모으고, 붙이고, 떠난다
이름 칸에 haneul을 치고 '후기 남기기'를 누르면 브라우저는 세 가지 일을 차례로 합니다.
- 모으기 — 폼 안 칸에서 값을 모읍니다. 이름 칸의 값은
haneul입니다. - 붙이기 — 지금 페이지 주소 뒤에
?기호를 붙이고nickname=haneul을 잇습니다. - 떠나기 — 그 주소로 페이지를 다시 받아 처음부터 그립니다. 링크를 누를 때처럼 브라우저가 그 주소의 페이지를 받아 지금 탭의 페이지를 바꿉니다(브라우저 규칙 1).
아래 잰 값은 이름 칸에 haneul을 치고 단추를 누른 뒤에 잰 것입니다.
<form>
<label for="nick">이름</label>
<input
id="nick"
name="nickname"
/>
<button type="submit">
후기 남기기
</button>
</form>form의 주소?nickname=haneul
form의 주소는 떠나 간 주소의 끝입니다. 내 파일에서 해 보면 주소창 끝에 ?nickname=haneul이 붙어 있습니다.
다시 받아 그린 페이지는 파일에 적힌 그대로라, 방금 친 haneul은 칸에 남아 있지 않습니다. 단추를 누르는 순간 화면이 한 번 깜빡이고 칸이 비는 까닭이 이것입니다. 위 결과 화면은 눌러도 떠나지 않아, 친 글이 칸에 남습니다.
글자 칸에서 Enter를 눌러도 같은 일이 일어납니다.
3action은 들고 갈 주소를 정한다
<form action="search.html">
<label for="q">찾을 요리</label>
<input id="q" name="q" />
<button type="submit">
찾기
</button>
</form>form의 주소search.html?q=kimchi
찾을 요리 칸에 kimchi를 치고 '찾기'를 누른 뒤의 주소입니다.
action에는 값을 들고 갈 주소를 적습니다. 링크의href처럼, 이 HTML 파일이 있는 폴더에서 출발합니다. 이 폼은 같은 폴더의search.html로 떠납니다.action을 적지 않으면 지금 페이지 주소로 갑니다. 2절의 주소가 지금 페이지 뒤에 값만 붙은 꼴이었던 까닭입니다.method는 값을 보내는 방법입니다. 적지 않으면get이고,get은 값을 주소 뒤에 붙입니다.method="post"로 적으면 값을 주소가 아니라 요청 안에 담아 보내는데, 받는 쪽 프로그램을 만들 때 쓰는 방법이라 이 과목에서는 쓰지 않습니다.
search.html이 kimchi로 레시피를 찾아 보이려면 주소의 값을 읽는 프로그램(서버나 JavaScript)이 있어야 합니다. HTML만으로는 받은 값을 쓰지 못합니다.
예제
레시피 노트 목록 페이지 index.html에 둘 후기 폼입니다. 이름과 만든 요리를 받습니다. 이름 칸에 haneul, 요리 칸에 kimchi를 치고 '후기 남기기'를 눌렀습니다.
<form>
<label for="nick">이름</label>
<input
id="nick"
name="nickname"
/>
<label for="food">요리</label>
<input
id="food"
name="food"
/>
<button type="submit">
후기 남기기
</button>
</form>form의 주소?nickname=haneul&food=kimchi#food의 값(없음)
칸이 둘이면 이름=값 조각을 & 기호로 잇고, 조각의 차례는 폼 안 칸의 차례입니다. #food의 값은 다시 그려진 페이지의 요리 칸에 든 값입니다 — 비어 있습니다.
자주 틀리는 곳
틀린 생각: 제출하면 친 값이 어딘가에 저장된다.
화면이 깜빡이고 칸이 비면, 값이 어딘가로 들어갔다고 여기게 됩니다.
<form>
<label for="nick">이름</label>
<input
id="nick"
name="nickname"
/>
<button type="submit">
후기 남기기
</button>
</form>form의 주소?nickname=haneul#nick의 값(없음)
값은 떠나 간 주소의 ? 뒤에만 있습니다. 주소창에서 ? 뒤를 지우고 다시 열면 haneul은 어디에도 없습니다. HTML 파일도 바뀌지 않았습니다.
맞는 규칙: 제출은 값을 주소에 붙여 떠나는 일까지입니다(브라우저 규칙 1). 받은 값을 저장하고 쓰는 것은 받는 쪽 프로그램(서버)의 일이고, 이 과목 밖입니다.
틀린 생각: 글자 칸에서 Enter를 누르면 줄이 바뀐다.
문서 편집기에서 Enter는 줄바꿈이라 칸에서도 그럴 것 같습니다.
<form>
<label for="nick">이름</label>
<input
id="nick"
name="nickname"
/>
<button type="submit">
후기 남기기
</button>
</form>form의 주소?nickname=haneul
이름 칸에서 Enter를 누르자 단추를 누른 것과 같은 주소로 떠났습니다.
맞는 규칙: input 글자 칸은 한 줄 칸이라 Enter가 줄바꿈이 아니라 제출입니다. 여러 줄을 받는 칸은 textarea이고, 그 안의 Enter는 줄바꿈입니다 — 여러 줄 글과 고르는 칸에서 봅니다.
틀린 생각: 같은 페이지에 있는 칸은 모두 함께 보내진다.
<form>
<label for="nick">이름</label>
<input
id="nick"
name="nickname"
/>
<button type="submit">
후기 남기기
</button>
</form>
<label for="memo">메모</label>
<input id="memo" name="memo" />form의 주소?nickname=haneul
메모 칸에 hi를 쳤지만 주소에 memo=hi가 없습니다. 메모 칸은 </form> 뒤에 있어 폼 밖입니다.
맞는 규칙: 보내지는 것은 그 form 요소 안에 든 칸뿐입니다. 함께 보낼 칸은 form 안으로 옮깁니다.
확인 문제
1. 예제의 후기 폼에서 form 여는 태그만 <form action="thanks.html">로 바꿨습니다. 같은 값(haneul · kimchi)을 치고 '후기 남기기'를 누르면 어디로 떠날까요?
<form action="thanks.html">
<label for="nick">이름</label>
<input
id="nick"
name="nickname"
/>
<label for="food">요리</label>
<input
id="food"
name="food"
/>
<button type="submit">
후기 남기기
</button>
</form>
- ① 지금 페이지 주소 — 뒤에 두 칸의 값이 붙는다
- ②
thanks.html— 뒤에 두 칸의 값이 붙는다 - ③
thanks.html— 값은 붙지 않는다
힌트
action이 정하는 것과, 모은 값을 붙이는 자리를 3절에서 찾아봅니다.
정답
② — thanks.html 뒤에 두 칸의 값이 붙습니다.
form의 주소thanks.html?nickname=haneul&food=kimchi
action은 들고 갈 주소를 같은 폴더의 thanks.html로 바꿉니다. 모은 값은 그 주소 뒤 ? 다음에 붙습니다.
- ①
action을 보지 않고 지금 페이지로 간다고 본 것입니다. 지금 페이지로 가는 것은action이 없을 때입니다. - ③
action이 있으면 값은 붙지 않는다고 본 것입니다.method를 적지 않은 폼(get)은 어느 주소로 가든 값을 그 뒤에 붙입니다.
2. 찾은 결과를 보이는 페이지 result.html로 값을 들고 가는 폼입니다. ____ 자리에 들어갈 것을 쓰세요.
<form ____>
<label for="q">찾을 요리</label>
<input id="q" name="q" />
<button type="submit">
찾기
</button>
</form>
힌트
들고 갈 주소를 적는 속성을 3절에서 찾아봅니다.
정답
action="result.html"입니다.
<form action="result.html">
<label for="q">요리</label>
<input id="q" name="q" />
<button type="submit">
찾기
</button>
</form>form의 주소result.html?q=kimchi
kimchi를 치고 누르면 result.html?q=kimchi로 떠납니다. 정답 칸이 좁아 라벨 글을 '요리'로 줄였습니다.
href="result.html"로 적으면 폼은 그 속성을 쓰지 않아 지금 페이지로 갑니다 — 링크의 갈 곳은 href, 폼의 갈 곳은 action입니다.
3. 여행 일정 페이지의 참가 신청 폼입니다. 이름 칸에 minji, 인원 칸에 2를 치고 '신청'을 눌렀더니 주소에 인원이 없습니다. 몇 번 줄을 어디로 옮겨야 할까요?
<form>
<label for="nm">이름</label>
<input
id="nm"
name="name"
/>
<button type="submit">
신청
</button>
</form>
<label for="pp">인원</label>
<input
id="pp"
name="people"
/>
힌트
인원 칸이 어느 요소 안에 들어 있는지 여는 태그와 닫는 태그를 따라가 봅니다.
정답
10번 줄 </form>을 맨 아래(15번 줄 뒤)로 옮깁니다. 인원 칸이 폼 안에 들어갑니다.
form의 주소?name=minji
<form>
<label for="nm">이름</label>
<input
id="nm"
name="name"
/>
<button type="submit">
신청
</button>
<label for="pp">인원</label>
<input
id="pp"
name="people"
/>
</form>form의 주소?name=minji&people=2
고치기 전에는 인원 칸이 </form> 뒤라 폼 밖이었습니다. 보내지는 것은 form 안의 칸뿐입니다(브라우저 규칙 1). 인원 칸을 단추 위로 옮겨도 됩니다 — 칸이 모두 폼 안이면 주소는 같습니다.
흔한 오답은 인원 칸에 name을 더 적는 답입니다. 인원 칸에는 이미 name="people"이 있습니다. 칸이 폼 밖이면 name이 있어도 보내지 않습니다.
컴퓨터에서 해 보기(선택) — 점수에 들지 않습니다. 폰으로만 보고 있다면 건너뛰세요.
예제의 후기 폼을 html-css-study 폴더에 review.html로 저장하고(문서 뼈대의 body 안에 예제 코드를 넣습니다), 두 칸에 글을 친 뒤 단추를 눌러 주소창 끝을 봅니다. 이어서 이름 칸에서 Enter를 누르면 무엇이 달라질지 먼저 적고, 눌러서 맞춰 봅니다.