Bài 4 · Vận dụng · 22 phút
Bảng & biểu mẫu (form)
Biên soạn bởi Nguyễn Anh Tuấn
Bảng table (thead/tbody/th scope) cho dữ liệu; biểu mẫu form với input gắn label đúng (for/id), các loại input, button và validation cơ bản của trình duyệt.
Có những nội dung tự nhiên xếp thành hàng và cột: bảng điểm, bảng giá, lịch học. Với loại dữ liệu đó, HTML có thẻ <table>. Một bảng gồm các hàng <tr> (table row), trong mỗi hàng là các ô. Ô tiêu đề là <th>, ô dữ liệu thường là <td>.
Bảng gọn gàng nên chia hai phần: <thead> chứa hàng tiêu đề, <tbody> chứa các hàng dữ liệu.
bang.html · bảng dữ liệu với thead và tbody (mở .html bằng trình duyệt)
<table>
<thead>
<tr>
<th>Tên</th>
<th>Tuổi</th>
<th>Món thích</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mun</td>
<td>2</td>
<td>Cá khô</td>
</tr>
<tr>
<td>Bông</td>
<td>1</td>
<td>Sữa ấm</td>
</tr>
</tbody>
</table> - ▸table chứa các hàng tr; mỗi hàng chứa các ô.
- ▸th là ô tiêu đề (tên cột/hàng); td là ô dữ liệu thường.
- ▸thead gom hàng tiêu đề, tbody gom các hàng dữ liệu.
Thêm một chi tiết nhỏ làm bảng dễ đọc hơn nhiều với người khiếm thị: thuộc tính scope trên thẻ th. Nó cho biết ô tiêu đề này là của một cột (scope="col") hay một hàng (scope="row"), để screen reader đọc mỗi ô dữ liệu kèm đúng tiêu đề của nó.
scope.html · báo th thuộc cột hay hàng
<tr>
<th scope="col">Tên</th>
<th scope="col">Tuổi</th>
</tr> Trung thực
Tới giờ trang chỉ HIỆN nội dung ra. Muốn trang nhận thông tin từ người dùng (đăng ký, đăng nhập, gửi góp ý), ta cần biểu mẫu - thẻ <form>. Hãy hình dung form như một tờ phiếu giấy: có nhiều ô để điền và một nút để nộp.
Ô điền phổ biến nhất là <input>. Cùng một thẻ input nhưng đổi type sẽ ra nhiều loại ô khác nhau: text (chữ), email (địa chỉ email), password (mật khẩu, hiện dấu chấm), number, date… Cuối form là một <button> để gửi.
form-co-ban.html · vài loại input và một nút gửi
<form>
<input type="text" />
<input type="email" />
<input type="password" />
<button type="submit">Gửi</button>
</form> - ▸form bọc các trường nhập và nút gửi - như một tờ phiếu.
- ▸input là ô nhập; đổi type để ra ô chữ, email, mật khẩu, số, ngày…
- ▸button type="submit" là nút nộp form.
Một ô input trơ trọi thì người dùng không biết phải điền gì. Mỗi ô cần một nhãn - thẻ <label>. Nhưng đặt chữ cạnh ô thôi chưa đủ: phải nối nhãn với ô bằng cặp thuộc tính for (của label) trùng với id (của input).
label.html · nối label với input qua for/id
<form>
<label for="ten">Tên của mèo con</label>
<input type="text" id="ten" />
<label for="email">Email</label>
<input type="email" id="email" />
</form> Liên kết này mang lại hai điều: bấm vào chữ nhãn thì con trỏ nhảy thẳng vào ô (vùng bấm rộng hơn, rất tiện trên điện thoại), và screen reader đọc đúng tên trường cho người khiếm thị - cùng tinh thần với thuộc tính alt cho ảnh ở bài Liên kết, ảnh & đa phương tiện. Đây cũng là một viên gạch của a11y: web cho mọi người - một thẻ nhỏ, khác biệt lớn.
- ▸Mỗi input cần một label cho biết phải nhập gì.
- ▸Nối label với input bằng for (label) trùng id (input).
- ▸Nối đúng thì bấm label là focus vào ô, và screen reader đọc đúng tên trường.
- ▸placeholder chỉ là gợi ý mờ trong ô, KHÔNG thay được label.
Điều bất ngờ dễ chịu: trình duyệt có sẵn một lớp kiểm tra cơ bản (validation) mà chưa cần JavaScript. Thêm required thì ô đó bắt buộc phải điền; đặt type="email" thì trình duyệt tự kiểm địa chỉ có đúng dạng email không khi bấm gửi.
validation.html · bắt buộc và kiểm định dạng, không cần JS
<form>
<label for="ten">Tên</label>
<input type="text" id="ten" required />
<label for="email">Email</label>
<input type="email" id="email" required />
<button type="submit">Đăng ký</button>
</form> Trung thực
Bước tiếp theo
Câu hỏi thường gặp
th (table header) là ô TIÊU ĐỀ - tên của một cột hoặc một hàng; trình duyệt thường in đậm và canh giữa nó. td (table data) là ô chứa DỮ LIỆU thường. Dùng th cho ô tiêu đề giúp người đọc lẫn screen reader biết mỗi ô dữ liệu thuộc về tiêu đề nào.
Không. Bảng chỉ dành cho DỮ LIỆU dạng hàng-cột (bảng điểm, bảng giá…). Dùng bảng để dàn bố cục là thói quen cũ đã bỏ: nó làm screen reader đọc sai, khó sửa, và khó co giãn trên điện thoại. Việc dàn bố cục là của CSS, học ở khoá sau.
Khi for của label trùng id của input, hai thứ được nối với nhau: bấm vào chữ label thì con trỏ nhảy ngay vào ô nhập (vùng bấm to hơn, tiện trên điện thoại), và screen reader đọc đúng tên trường khi người khiếm thị tới ô đó. Thiếu liên kết này thì ô nhập trở thành một ô vô danh.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Trong bảng, thẻ nào dùng cho ô TIÊU ĐỀ (tên cột hoặc hàng)?
- 1
Bảng điểm của mèo con
Dựng một bảng 3 cột (Môn, Điểm, Xếp loại) với hàng tiêu đề và 2 hàng dữ liệu, dùng thead và tbody.
✅ Hoàn thành khi: Có <table> với <thead> (một <tr> chứa 3 <th>) và <tbody> (2 <tr>, mỗi tr 3 <td>).
- 2
Thêm scope
Thêm scope cho các th trong hàng tiêu đề của bảng trên.
✅ Hoàn thành khi: Mỗi <th> tiêu đề cột có scope="col".
- 3
Bảng hay không bảng?
Với mỗi thứ, nên dùng bảng table hay không: (a) bảng giá 3 gói dịch vụ; (b) chia trang thành cột trái - cột phải cho đẹp.
✅ Hoàn thành khi: (a) dùng table vì là dữ liệu hàng-cột; (b) KHÔNG dùng table - đó là bố cục, để CSS lo.
- 4
Một form đăng ký
Viết một form có ô nhập Tên, ô nhập Email và một nút "Đăng ký", mỗi ô nhập có label gắn đúng.
✅ Hoàn thành khi: Có <form> chứa 2 cặp label+input (for trùng id) và một <button> gửi.
- 5
Bắt buộc và đúng định dạng
Sửa form trên để ô Tên bắt buộc nhập, và ô Email phải đúng định dạng email.
✅ Hoàn thành khi: input Tên có thuộc tính required; input Email có type="email".
- 6
Sửa lỗi label rời
Cho <label>Email</label><input id="mail" />. Chỉ ra vì sao label này chưa nối với ô nhập và sửa lại.
✅ Hoàn thành khi: Nêu: label thiếu for; sửa thành <label for="mail">Email</label> để for trùng id="mail".