Skip to content

disabled / readonly

disabledreadonly 都是用于限制用户编辑表单控件的属性,但两者的行为差异很大:disabled 使控件完全不可交互且值不会提交,readonly 使控件不可编辑但值会随表单提交。理解两者的区别对于构建条件性表单至关重要。

前置知识

阅读本节前,建议先了解:minlength / maxlength

基础概念

disabled 禁用

disabled 属性使控件完全不可用:

  • 不可交互:无法获得焦点、无法编辑、无法点击
  • 灰色显示:浏览器默认降低不透明度
  • 不提交数据:表单提交时包含 disabled 控件
  • 不参与验证:即使有 required,也不会验证

readonly 只读

readonly 属性使控件只可查看不可编辑:

  • 可聚焦:可以获得焦点、可以选中文本
  • 正常显示:外观与正常控件一致
  • 提交数据:值会随表单提交
  • 参与验证requiredpattern 等验证仍然有效

对比表

特性disabledreadonly
可编辑❌ 不可编辑❌ 不可编辑
可聚焦❌ 不可聚焦✅ 可以聚焦
可选中/复制
值是否提交不提交提交
参与验证❌ 不参与✅ 参与
默认样式灰色正常
适用元素所有表单控件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&note=编辑中</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 可以精确控制不同状态的样式。

最佳实践

  1. 不可修改的数据用 readonly:如订单号、创建时间等需要提交但不可改的值
  2. 不适用的选项用 disabled:如灰色的选项按钮、未激活的功能
  3. 配合 CSS 样式区分:让用户清晰分辨可编辑、只读和禁用字段
  4. 替代 disabled 数据传递:需要提交 disabled 的值时用 hidden 字段
  5. fieldset 批量禁用:使用 fieldset:disabled 批量控制整组字段

下一节

继续学习:autofocus / tabindex

参考链接