disabled / readonly
disabled 和 readonly 都是用于限制用户编辑表单控件的属性,但两者的行为差异很大:disabled 使控件完全不可交互且值不会提交,readonly 使控件不可编辑但值会随表单提交。理解两者的区别对于构建条件性表单至关重要。
前置知识
阅读本节前,建议先了解:minlength / maxlength
基础概念
disabled 禁用
disabled 属性使控件完全不可用:
- 不可交互:无法获得焦点、无法编辑、无法点击
- 灰色显示:浏览器默认降低不透明度
- 不提交数据:表单提交时包含 disabled 控件
- 不参与验证:即使有
required,也不会验证
readonly 只读
readonly 属性使控件只可查看不可编辑:
- 可聚焦:可以获得焦点、可以选中文本
- 正常显示:外观与正常控件一致
- 提交数据:值会随表单提交
- 参与验证:
required、pattern等验证仍然有效
对比表
| 特性 | disabled | readonly |
|---|---|---|
| 可编辑 | ❌ 不可编辑 | ❌ 不可编辑 |
| 可聚焦 | ❌ 不可聚焦 | ✅ 可以聚焦 |
| 可选中/复制 | ❌ | ✅ |
| 值是否提交 | ❌ 不提交 | ✅ 提交 |
| 参与验证 | ❌ 不参与 | ✅ 参与 |
| 默认样式 | 灰色 | 正常 |
| 适用元素 | 所有表单控件 | text, search, url, tel, email, password, number, textarea |
语法
disabled 用法
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>disabled 示例</title>
</head>
<body>
<h2>disabled 演示</h2>
<form action="/submit" method="get">
<div>
<label for="username">用户名:</label>
<input type="text" id="username" name="username" value="admin">
</div>
<div>
<label for="role">角色:</label>
<!-- 禁用:不可编辑,值不提交 -->
<input type="text" id="role" name="role" value="管理员" disabled>
</div>
<div>
<label>
<input type="checkbox" disabled>
此选项已禁用
</label>
</div>
<button type="submit">提交</button>
</form>
<p>提交后 URL 将只包含 username=admin(不含 role)</p>
</body>
</html>readonly 用法
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>readonly 示例</title>
</head>
<body>
<h2>readonly 演示</h2>
<form action="/submit" method="get">
<div>
<label for="user-id">用户 ID:</label>
<!-- 只读:不可编辑,但值会提交 -->
<input type="text" id="user-id" name="user_id" value="1024" readonly>
</div>
<div>
<label for="name">姓名:</label>
<input type="text" id="name" name="name" value="张三">
</div>
<button type="submit">提交</button>
</form>
<p>提交后 URL 将包含 user_id=1024&name=张三</p>
</body>
</html>详细说明
提交数据差异
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>提交差异</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
table { border-collapse: collapse; width: 100%; }
th, td { padding: 8px; border: 1px solid #ddd; text-align: left; }
input { padding: 6px 10px; border: 2px solid #ddd; border-radius: 4px; }
</style>
</head>
<body>
<h2>disabled vs readonly 提交差异</h2>
<form action="/submit" method="get">
<table>
<tr>
<th>字段</th><th>值</th><th>状态</th>
</tr>
<tr>
<td>订单号</td>
<td><input type="text" name="order_id" value="ORD-001" readonly></td>
<td>readonly → <strong>提交</strong></td>
</tr>
<tr>
<td>创建时间</td>
<td><input type="text" name="created_at" value="2025-07-14" disabled></td>
<td>disabled → <strong>不提交</strong></td>
</tr>
<tr>
<td>备注</td>
<td><input type="text" name="note" value="编辑中"></td>
<td>正常 → <strong>提交</strong></td>
</tr>
</table>
<button type="submit">提交查看 URL</button>
</form>
<p>URL 只会包含:order_id=ORD-001¬e=编辑中</p>
</body>
</html>CSS 样式控制
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>disabled/readonly CSS</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
.form-group { margin-bottom: 12px; }
label { display: block; margin-bottom: 4px; font-weight: 600; }
input {
width: 100%;
padding: 8px 12px;
border: 2px solid #ddd;
border-radius: 6px;
box-sizing: border-box;
font-size: 16px;
}
/* 默认 disabled 样式(浏览器自带灰色) */
input:disabled {
opacity: 0.5;
cursor: not-allowed;
background: #f5f5f5;
}
/* readonly 样式 */
input:read-only {
background: #f8f9fa;
border-color: #ccc;
cursor: default;
}
/* 正常状态 */
input:read-write {
border-color: #4a90d9;
}
/* :disabled 和 :read-only 伪类 */
input:disabled:hover { cursor: not-allowed; }
input:read-only:focus { outline: none; }
</style>
</head>
<body>
<h2>状态样式</h2>
<form>
<div class="form-group">
<label for="editable">可编辑:</label>
<input type="text" id="editable" name="editable" value="可以修改">
</div>
<div class="form-group">
<label for="read-only-field">只读:</label>
<input type="text" id="read-only-field" name="readonly" value="只读内容" readonly>
</div>
<div class="form-group">
<label for="disabled-field">禁用:</label>
<input type="text" id="disabled-field" name="disabled" value="禁用内容" disabled>
</div>
</form>
</body>
</html>JavaScript 动态切换
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>动态切换</title>
</head>
<body>
<h2>条件性禁用</h2>
<form>
<div>
<label>
<input type="checkbox" id="has-discount" onchange="toggleDiscount(this.checked)">
使用优惠券
</label>
</div>
<div>
<label for="discount-code">优惠券码:</label>
<!-- 未勾选时禁用 -->
<input type="text" id="discount-code" name="discount_code" disabled placeholder="请先勾选上方选项">
</div>
<div>
<label for="order-id">订单号:</label>
<input type="text" id="order-id" name="order_id" value="ORD-20250714" readonly>
</div>
</form>
<script>
function toggleDiscount(checked) {
const codeInput = document.getElementById('discount-code');
codeInput.disabled = !checked;
if (checked) {
codeInput.placeholder = '请输入优惠码';
codeInput.focus();
} else {
codeInput.value = '';
codeInput.placeholder = '请先勾选上方选项';
}
}
</script>
</body>
</html>fieldset 批量 disabled
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>fieldset 批量 disabled</title>
</head>
<body>
<h2>批量禁用</h2>
<form>
<fieldset id="address-group">
<legend>收货地址</legend>
<label>
<input type="checkbox" id="use-address" onchange="toggleAddress(this.checked)" checked>
需要填写地址
</label>
<div>
<label for="province">省份:</label>
<select id="province" name="province">
<option>北京</option>
<option>上海</option>
</select>
</div>
<div>
<label for="detail">详细地址:</label>
<input type="text" id="detail" name="detail">
</div>
</fieldset>
</form>
<script>
function toggleAddress(checked) {
document.getElementById('address-group').disabled = !checked;
}
</script>
</body>
</html>实战示例
编辑表单中的只读字段
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>编辑表单</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 40px auto; }
.form-group { margin-bottom: 12px; }
label { display: block; font-weight: 600; margin-bottom: 4px; }
input, textarea {
width: 100%;
padding: 8px 12px;
border: 2px solid #ddd;
border-radius: 6px;
box-sizing: border-box;
}
input:read-only, textarea:read-only {
background: #f8f9fa;
}
.editable input:not(:read-only) { border-color: #4a90d9; }
button {
padding: 10px 24px;
background: #4a90d9;
color: #fff;
border: none;
border-radius: 6px;
cursor: pointer;
}
</style>
</head>
<body>
<h2>编辑订单</h2>
<form>
<!-- 不可修改的信息 -->
<div class="form-group">
<label>订单号:</label>
<input type="text" name="order_id" value="ORD-20250714-001" readonly>
</div>
<div class="form-group">
<label>创建时间:</label>
<input type="text" name="created_at" value="2025-07-14 10:30" disabled>
</div>
<hr>
<!-- 可修改的信息 -->
<div class="form-group editable">
<label for="address">收货地址:</label>
<input type="text" id="address" name="address" value="北京市海淀区xxx路xxx号">
</div>
<div class="form-group editable">
<label for="remark">备注:</label>
<textarea name="remark" rows="3">请尽快发货</textarea>
</div>
<button type="submit">保存修改</button>
</form>
</body>
</html>注意事项
disabled 控件不可聚焦
disabled 的控件无法通过 Tab 键导航到,也无法被屏幕阅读器访问到内容。
disabled 不提交,需要替代方案
如果需要在服务端获取 disabled 控件的值,可以改用 readonly 或添加 type="hidden":
html
<!-- 方案一:使用 readonly(可聚焦但不可编辑) -->
<input type="text" name="id" value="42" readonly>
<!-- 方案二:hidden + disabled 显示 -->
<input type="hidden" name="id" value="42">
<input type="text" value="42" disabled>CSS :disabled 和 :read-only
使用 CSS 伪类 :disabled、:read-only、:read-write 可以精确控制不同状态的样式。
最佳实践
- 不可修改的数据用 readonly:如订单号、创建时间等需要提交但不可改的值
- 不适用的选项用 disabled:如灰色的选项按钮、未激活的功能
- 配合 CSS 样式区分:让用户清晰分辨可编辑、只读和禁用字段
- 替代 disabled 数据传递:需要提交 disabled 的值时用 hidden 字段
- fieldset 批量禁用:使用
fieldset:disabled批量控制整组字段
下一节
继续学习:autofocus / tabindex