label 元素的作用
<label> 为表单字段命名。用 for 关联它,并把值设为字段的 id,就会发生两件事:字段获得焦点时,屏幕阅读器会读出标签;点击标签文字时,字段会获得焦点。点击下面的两段文字试试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Label</title>
<style>
body { font-family: system-ui, sans-serif; }
p { margin: 0 0 12px; }
</style>
</head>
<body>
<p>
<label for="city">City (a label)</label>
<input id="city" name="city">
</p>
<p>
<span>Country (plain text)</span>
<input name="country">
</p>
</body>
</html>Master HTML the hands-on way
Interactive lessons, real projects, and instant feedback.
START NOW
点击“City”会把光标放进它的字段。点击“Country”则什么也不会发生,屏幕阅读器聚焦到第二个字段时,只会读出“edit text”(编辑文本),没有名字。二者看起来一模一样,但只有一个有标签。
关联标签的两种方式
使用 for 和 id,或者把字段放在标签里面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>for vs wrapping</title>
<style>
body { font-family: system-ui, sans-serif; }
.row { margin-bottom: 12px; }
label { font-weight: 600; }
</style>
</head>
<body>
<form>
<!-- 1. for + id: label and field can be anywhere -->
<div class="row">
<label for="email">Email</label><br>
<input type="email" id="email" name="email">
</div>
<!-- 2. wrapping: no id needed -->
<div class="row">
<label>Phone <input type="tel" name="phone"></label>
</div>
<button type="submit">Save</button>
</form>
</body>
</html>
for 和 id包裹 需要 id 是,并且在页面中唯一 否 标签和字段可以分开 可以(表格单元格、网格) 不可以,字段在标签里面 容易出错的地方 拼写错误或重复的 id 在一个标签里放了两个字段
for 必须与字段的 id 一致,而不是它的 name。二者常常是同一个词,这会掩盖错误,直到有人改了其中一个。两种方式同时使用(包裹并加上 for)也没问题,而且很常见。
标签可以关联 <input>(type="hidden" 除外)、<select>、<textarea>、<button>、<meter>、<output> 和 <progress>。一个标签只为一个字段命名。一个字段可以有多个标签,不过一个清晰的标签对所有人都更友好。
为复选框和单选按钮扩大点击区域
对于小控件,标签最重要:点击标签上的任何位置都会切换勾选框,所以点击区域是整行文字,而不是一个 13 像素的小方块。给标签加上样式,还能让点击区域更大:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Click target</title>
<style>
body { font-family: system-ui, sans-serif; }
.option {
display: flex;
align-items: center;
gap: 10px;
max-width: 320px;
padding: 12px;
margin-bottom: 8px;
border: 1px solid #e5e7eb;
border-radius: 8px;
cursor: pointer;
}
.option:hover { border-color: #2563eb; }
</style>
</head>
<body>
<form>
<label class="option">
<input type="checkbox" name="alerts" value="email"> Email me about new courses
</label>
<span class="option">
<input type="checkbox" name="alerts" value="sms"> Not a label: only the box works
</span>
<button type="submit">Save</button>
</form>
</body>
</html>
点击每一行远离勾选框的空白处。第一行会切换;第二行除非你正好点中勾选框本身,否则什么也不会发生。关于复选框的更多内容,请看 HTML 复选框 。
提示和错误信息
标签应该简短:就是字段的名字。额外的说明和错误信息放在单独的元素中,用 aria-describedby 关联,这样屏幕阅读器会先读标签,再读说明:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hints and errors</title>
<style>
body { font-family: system-ui, sans-serif; }
label { display: block; font-weight: 600; }
.hint { display: block; color: #4b5563; font-size: 14px; margin: 2px 0 6px; }
.error { color: #b91c1c; font-size: 14px; margin: 4px 0 0; }
input { font: inherit; padding: 4px 8px; }
.req { color: #b91c1c; }
</style>
</head>
<body>
<form novalidate>
<label for="user">Username <span class="req" aria-hidden="true">*</span></label>
<span class="hint" id="user-hint">3 to 16 lowercase letters or digits</span>
<input id="user" name="username" required pattern="[a-z0-9]{3,16}"
aria-describedby="user-hint user-error">
<p class="error" id="user-error"></p>
<button type="submit">Create</button>
</form>
<script>
const form = document.querySelector('form');
const user = document.querySelector('#user');
form.addEventListener('submit', (event) => {
const error = document.querySelector('#user-error');
if (!user.checkValidity()) {
event.preventDefault();
error.textContent = user.value ? 'Use 3 to 16 lowercase letters or digits.' : 'Enter a username.';
user.setAttribute('aria-invalid', 'true');
user.focus();
} else {
error.textContent = '';
user.removeAttribute('aria-invalid');
}
});
</script>
</body>
</html>
先在字段为空时点击 Create,再分别输入 AB 和 ada99 试试。有了 aria-describedby,屏幕阅读器会读出类似“Username, required, edit text, 3 to 16 lowercase letters or digits, Enter a username.”的内容。星号设置了 aria-hidden,因为 required 属性已经会让屏幕阅读器读出“required”(必填);再听到一句“star”(星号)没有任何帮助。
隐藏的标签
有些字段除了文字标签之外还有别的可见提示,比如旁边有 Search 按钮的搜索框。这时仍然需要标签;在视觉上隐藏它,但把它留在页面中给屏幕阅读器使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Hidden label</title>
<style>
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
input, button { font: inherit; padding: 6px 10px; }
</style>
</head>
<body>
<form role="search">
<label for="q" class="visually-hidden">Search courses</label>
<input type="search" id="q" name="q" placeholder="e.g. Python">
<button type="submit">Search</button>
</form>
</body>
</html>
不要用 display: none 或 visibility: hidden 隐藏它:这样也会对屏幕阅读器隐藏,而且并非所有浏览器和屏幕阅读器都还会把隐藏的标签当作字段名。另一种做法是在 input 上写 aria-label="Search courses",不需要任何 label 元素就能为它命名。只要有空间,可见的标签仍然是最好的选择:能看到字段的用途,对每个人都有好处。
常见错误
for 指向了 name ,而不是 id。什么都没有关联上。
重复的 id。 for 会关联到第一个带有该 id 的元素,那可能是页面上另一个表单中的字段。
用 placeholder 代替标签。 一输入就消失,也不是可靠的字段名。
一个标签里放了两个字段。 一个标签只为一个字段命名;第二个字段就没有标签了。
复选框的标签里放了链接 ,比如“我接受条款”,其中“条款”是链接。这一行有的部分切换勾选框,有的部分打开页面,很容易点错。把链接放到标签外面。
用 display: none 隐藏标签。 改用视觉隐藏的类。
字段旁边的文字不是 <label>。 看起来一样,却不起任何作用。关于包裹这些字段的表单,请看 HTML 表单 。