textarea实现只读且保留换行缩进需三要素:readonly属性、wrap="off"、white-space:pre+monospace字体,缺一不可;否则空格压缩、长行折行或格式丢失。

用 <textarea> 实现只读但保留换行缩进的文本显示
直接用 <textarea> 是最稳妥的选择——它原生支持换行、空格、制表符等格式占位符,且设为 readonly 后用户无法编辑,又比 <pre> 更容易控制宽高和字体一致性。
常见错误是只加 readonly 却忽略 wrap="off" 和 CSS 重置,导致长行自动折行、空格被压缩。实际使用时需同时处理三处:
-
readonly属性必须显式写上(仅disabled会变灰且提交时丢值) - 加上
wrap="off"防止浏览器对长文本自动换行(尤其 Chrome/Firefox 默认wrap="soft") - CSS 中设置
white-space: pre; font-family: monospace;确保空格、制表符不被合并,等宽字体对齐更准
示例:
<textarea readonly wrap="off" style="white-space: pre; font-family: monospace; width: 100%; height: 120px; border: 1px solid #ccc; padding: 8px;">Name: Alice Age: 32 City: New York</textarea>
为什么不用 <pre> + <code>?
<pre> 确实保留空白符,但它是块级元素,无法像表单控件那样统一设置尺寸、边框或聚焦样式;更关键的是,它不支持 readonly 语义,用户仍可全选复制,但无法通过键盘导航到其中(比如 Tab 键跳过),在表单流中体验割裂。
立即学习“前端免费学习笔记(深入)”;
如果硬要用 <pre>,必须额外加 tabindex="-1" 阻止焦点进入,并用 CSS 模拟禁用态(如 opacity: 0.7;),但这样无法阻止右键“全选”或双击选词——而 <textarea readonly> 浏览器原生屏蔽所有编辑行为,包括拖拽选中后粘贴覆盖。
contenteditable="false" 在 <div> 上可行吗?
技术上可以,但不推荐。虽然 <div contenteditable="false"> 能显示格式化文本,但它:不参与表单序列化(form.submit() 不包含其内容)、无障碍支持差(屏幕阅读器可能忽略其只读状态)、移动端光标行为不稳定(iOS Safari 偶尔仍唤出键盘)。更重要的是,contenteditable 的 false 值并非标准属性,部分老浏览器会直接忽略,退化为可编辑状态。
若必须用 div(例如嵌入富文本预览),至少补上:aria-readonly="true"、tabindex="-1"、user-select: none;,并手动监听 keydown 阻止 Backspace/Delete。
格式占位符失效的典型场景与修复
最常踩的坑是后端返回的文本含 \r\n 换行符,但前端直接插入 <textarea> 时被浏览器转义成普通空格;或者用了 innerText 赋值(会压缩空白),而非 textContent 或直接 innerHTML。
- 服务端返回 JSON 字段时,确保换行符未被 JSON 库二次转义(如 Python
json.dumps()默认不转义 \n,但某些配置会加反斜杠) - JS 赋值时用
el.textContent = str;,别用el.innerText = str;(后者会按渲染规则折叠空白) - 若文本来自用户输入再回显,注意 HTML 实体编码:原始字符串中的
不会被<textarea>解析为空格,应保持纯文本传入
复杂点在于混合了 Markdown 或 ANSI 转义色码的文本——这时 <textarea> 只能显示原始字符,无法渲染颜色或样式,得换方案(如用 <pre> + highlight.js),但那就超出“只读+格式占位符”的基本需求了。



















