<input> 是一个表单字段,它的 type 属性决定字段的种类。同一个标签可以做成文本框、滑块、日期选择器或颜色选择器。试试下面的每个字段,然后点击 Submit,看看表单会发送什么:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Input types</title>
<style>
body { font-family: system-ui, sans-serif; }
label { display: grid; grid-template-columns: 90px auto; align-items: center; gap: 8px; margin-bottom: 8px; }
</style>
</head>
<body>
<form>
<label>text <input type="text" name="text" value="Hello"></label>
<label>email <input type="email" name="email" value="ada@example.com"></label>
<label>password <input type="password" name="password" value="secret"></label>
<label>number <input type="number" name="number" value="3" min="1" max="10"></label>
<label>range <input type="range" name="range" min="0" max="100" value="40"></label>
<label>date <input type="date" name="date" value="2026-09-24"></label>
<label>color <input type="color" name="color" value="#2563eb"></label>
<label>checkbox <input type="checkbox" name="checkbox" value="on" checked></label>
<button type="submit">Submit</button>
</form>
</body>
</html>
<input> 是空元素,所以没有结束标签。它的 name 是发送值时使用的键名,value 是初始值。缺少 type 或拼错时,得到的是普通文本框。
type | 是什么 | 说明 |
|---|
text | 单行文本 | 默认值 |
password | 以圆点显示的文本 | 本身不加密;要通过 HTTPS 发送 |
email | 电子邮件地址 | 验证格式;手机键盘上有 @ 键 |
url | 网址 | 必须以 https:// 这样的协议开头 |
tel | 电话号码 | 手机上弹出拨号键盘,不检查格式 |
search | 搜索框 | 通常会显示清除按钮 |
number | 数字 | 增减按钮,min、max、step |
range | 滑块 | 本身就不精确;值是一个数字 |
date | 日期 | 值为 YYYY-MM-DD |
time | 一天中的时间 | 值为 HH:MM(24 小时制) |
datetime-local | 日期和时间,不带时区 | 值为 YYYY-MM-DDTHH:MM |
month | 年和月 | 并非所有浏览器都支持 |
week | 年和周数 | 并非所有浏览器都支持 |
color | 颜色选择器 | 值为小写的 #rrggbb |
checkbox | 开关式的勾选框 | 参见 HTML 复选框 |
radio | 一组选项中选一个 | 参见 HTML 单选按钮 |
file | 文件选择器 | accept、multiple |
hidden | 发送但不显示的值 | 用于 ID 和令牌 |
submit | 提交按钮 | <button type="submit"> 更灵活 |
reset | 重置按钮 | 很少是好主意 |
button | 本身不做任何事的按钮 | 配合 JavaScript 使用 |
image | 以图片形式显示的提交按钮 | 还会发送点击坐标 |
文本类类型与手机键盘
在电脑上,email、url、tel、search 和 text 看起来都是文本框。区别在于验证,以及在手机上弹出哪种键盘。这个示例中,边框会根据浏览器对值的判断变成绿色或红色:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Text types</title>
<style>
body { font-family: system-ui, sans-serif; }
label { display: block; margin-bottom: 10px; }
input { display: block; font: inherit; margin-top: 4px; padding: 4px 8px; border: 2px solid #9ca3af; border-radius: 6px; }
input:valid { border-color: #16a34a; }
input:invalid { border-color: #dc2626; }
</style>
</head>
<body>
<form>
<label>email <input type="email" name="email" value="ada@example"></label>
<label>url <input type="url" name="site" value="example.com"></label>
<label>tel <input type="tel" name="phone" value="+1 555 0100"></label>
<label>text with inputmode="numeric" <input type="text" name="zip" inputmode="numeric" pattern="[0-9]{5}" value="02134"></label>
<button type="submit">Submit</button>
</form>
</body>
</html>
- 对浏览器来说,
ada@example 是有效的邮箱:它只检查有文字、有 @、有域名,并不检查域名中是否有点。真正的检查在服务器上进行。
example.com 不是有效的 url,因为它没有协议。https://example.com 才是。
tel 接受任何内容。各国的电话格式差别太大,所以没有内置检查;需要的话就加上 pattern。
inputmode="numeric" 让手机弹出数字键盘,又没有 type="number" 的那些问题,所以它是邮政编码、一次性验证码和银行卡号的正确选择。
number 和 range
二者都接受 min、max 和 step。number 用于精确的值;range 是滑块,适合对具体数字要求不高的值。range 滑块不显示数字,所以要搭配一个 <output>:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>number and range</title>
<style>
body { font-family: system-ui, sans-serif; }
label { display: block; margin-bottom: 12px; }
</style>
</head>
<body>
<form>
<label>Tickets
<input type="number" name="tickets" min="1" max="8" step="1" value="2">
</label>
<label>Price per kg
<input type="number" name="price" min="0" step="0.01" value="4.99">
</label>
<label>Volume
<input type="range" name="volume" id="volume" min="0" max="100" step="5" value="60">
<output for="volume" id="shown">60</output>
</label>
<button type="submit">Submit</button>
</form>
<script>
const volume = document.querySelector('#volume');
volume.addEventListener('input', () => {
document.querySelector('#shown').textContent = volume.value;
});
</script>
</body>
</html>
number 的 step 默认为 1,所以没有写 step="0.01" 的价格字段在提交表单时会拒绝 4.99。在 JavaScript 中,input.value 始终是字符串;要得到数字,用 input.valueAsNumber。
日期和时间
日期和时间类型会打开浏览器自带的选择器。读者看到的格式跟随其地区设置(09/24/2026、24.09.2026),但值始终是同一种固定格式:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Date and time</title>
<style>
body { font-family: system-ui, sans-serif; }
label { display: block; margin-bottom: 10px; }
code { background: #e5e7eb; padding: 2px 6px; }
</style>
</head>
<body>
<form>
<label>date <input type="date" name="date" value="2026-09-24" min="2026-01-01"></label>
<label>time <input type="time" name="time" value="14:30"></label>
<label>datetime-local <input type="datetime-local" name="when" value="2026-09-24T14:30"></label>
</form>
<p>Values: <code id="out"></code></p>
<script>
const form = document.querySelector('form');
const show = () => {
document.querySelector('#out').textContent =
[...form.elements].map((f) => f.value).join(' | ');
};
form.addEventListener('input', show);
show();
</script>
</body>
</html>
服务器收到的、JavaScript 读到的都是这种固定格式,所以你永远不需要解析“24.09.2026”。min 和 max 也使用同样的格式。datetime-local 不带时区:如果时区很重要,就在服务器上按读者所在的时区进行转换。
color 和 file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>color and file</title>
<style>
body { font-family: system-ui, sans-serif; }
label { display: block; margin-bottom: 12px; }
#swatch { display: inline-block; width: 60px; height: 24px; border-radius: 4px; vertical-align: middle; }
</style>
</head>
<body>
<form>
<label>Theme color <input type="color" name="color" id="color" value="#16a34a"></label>
<p>Preview: <span id="swatch"></span></p>
<label>Photos <input type="file" name="photos" accept="image/*" multiple></label>
<button type="submit">Submit</button>
</form>
<script>
const color = document.querySelector('#color');
const paint = () => { document.querySelector('#swatch').style.background = color.value; };
color.addEventListener('input', paint);
paint();
</script>
</body>
</html>
accept="image/*" 把文件选择器限制为图片(在手机上还会提供拍照选项);它也接受扩展名,比如 accept=".pdf,.docx"。它只是给选择器的提示,所以要在服务器上检查文件类型。multiple 允许选择多个文件。真正上传文件时,表单上还需要 method="post" 和 enctype="multipart/form-data"。
用 datalist 提供建议
<datalist> 给文本框提供一组建议,同时仍然允许输入任意值。用 list 属性把它们关联起来:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>datalist</title>
</head>
<body>
<form>
<label>Language
<input name="language" list="languages" placeholder="Start typing">
</label>
<datalist id="languages">
<option value="JavaScript"></option>
<option value="Python"></option>
<option value="Java"></option>
<option value="Rust"></option>
</datalist>
<button type="submit">Submit</button>
</form>
</body>
</html>
在字段中输入“ja”,就能看到匹配的建议。与 select 不同,读者可以输入列表中没有的值。
| 属性 | 作用 |
|---|
name | 提交值时使用的键名 |
value | 初始值 |
placeholder | 字段为空时显示的提示(不是标签) |
required | 提交前必须填写 |
disabled | 不能使用,也不会被提交 |
readonly | 不能编辑,但会被提交 |
autocomplete | 自动填充的内容:email、name、current-password、one-time-code、off |
min、max、step | 数字、范围、日期和时间的限制 |
minlength、maxlength | 文本类类型的长度限制 |
pattern | 整个值必须匹配的正则表达式 |
inputmode | 手机上显示哪种键盘:numeric、decimal、email、tel、url |
list | 某个 <datalist> 的 id |
multiple | 多个值,用于 email 和 file |
accept | file 允许的文件类型 |
常见错误
- 电话号码、邮政编码或银行卡号用
type="number"。 它们不是数量。用 tel,或者 text 加 inputmode="numeric"。
- 价格字段没有写
step="0.01"。 小数值会验证失败。
- 把
placeholder 当作标签。 读者一开始输入它就消失了。
- 靠
accept 或 type="email" 保证安全。 它们只是方便用户;服务器还要再检查一遍。
- 使用
type="month" 或 type="week" 却没有后备方案。 有些浏览器只会显示普通文本框。
- 写了结束标签
</input>。 <input> 是空元素。