kbd 与 samp 必须并列而非嵌套,因二者分别表示用户输入与程序输出这两个时序独立的语义;错误嵌套会混淆屏幕阅读器;正确结构为 prompt + kbd + samp 并列于 pre 内,并显式设置 samp 的等宽字体与 white-space: pre。

kbd 里不能直接嵌套 samp
浏览器不禁止这种写法,但语义完全错位:kbd 表示“用户键入的动作”,samp 表示“程序返回的结果”,两者是时间上先后发生的独立事件,不是父子关系。强行嵌套会导致屏幕阅读器把输出内容误读为输入的一部分,辅助技术无法区分“你敲了什么”和“系统回了什么”。
常见错误示例:<kbd>npm run dev</kbd><samp>vite v5.4.8\n ready in 123ms.</samp> —— 这段 HTML 把命令和输出放在同一层级是对的,但用 kbd 包住整个块再塞 samp 就破坏了语义边界。
终端交互排版的正确结构是并列而非嵌套
真实终端场景中,输入提示符、用户输入、换行、输出内容是线性时序关系,HTML 应用并列标签还原这一流程:
-
kbd只包裹纯输入文本(不含提示符,如$或>) - 提示符本身用
span或kbd(若视为界面控件,非语义输入) -
samp每行独立包裹,保留原始换行;多行输出不要用多个samp拼接,而应让单个samp内含\n并配合white-space: pre - 若需整体容器控制样式(如加边框、背景),用
div或pre外层包裹,内部保持kbd和samp平级
正确示例:
<pre class="terminal"> <span class="prompt">$</span> <kbd>node -v</kbd> <samp>v20.11.1</samp>
样式冲突:samp 在 pre 里可能被重置
很多 CSS 重置库(如旧版 Normalize.css)会把 samp 的 font-family 设为 inherit,导致它在 pre 中失去等宽效果,看起来和普通文本一样。这不是 bug,而是样式覆盖。
必须显式加固:
- 确保
samp有独立font-family声明,不依赖pre继承 - 避免给外层
pre设font-family: inherit - 检查是否意外设置了
samp { display: block }—— 它本是行内元素,块级化会破坏与kbd的水平对齐
最小可用样式:
samp {
font-family: ui-monospace, "SFMono-Regular", Consolas, monospace;
white-space: pre;
}
复杂输出(含缩进/堆栈)别硬塞 samp
samp 适合短小、线性的程序输出,比如命令回显、HTTP 状态行、简单日志。遇到带缩进的错误堆栈、JSON 响应体、多级缩进的 tree 输出,继续用 samp 会丢失结构语义,也难控制格式。
此时应切换方案:
- 完整堆栈 → 用
pre+code,语义更准(这是可复制的原始数据,不是“样本”) - 带语法高亮的响应体 →
pre+code+ Prism/Highlight.js - 需要点击复制的终端块 → 外层
div控制交互,内部仍保持kbd/samp并列,不要为了“看起来像终端”而牺牲语义
最容易被忽略的一点:samp 不处理换行逻辑,它只负责语义。换行是否生效,取决于父容器的 white-space 和字体是否支持等宽空格 —— 这部分得靠 CSS 实锤,不能指望标签自己扛。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











