该用samp,但仅当是程序真实运行后用户在终端、控制台或GUI中实际看到的原始输出文本;需配合pre保留换行,显式设置等宽字体,并严格区分code(代码)、kbd(输入)与samp(输出)的语义边界。

控制台输出该不该用 samp?先看它是不是“真输出”
不是所有看起来像终端的文字都适合套 samp。它只认一种东西:程序运行后,用户在终端、浏览器控制台或 GUI 提示框里**真实看到的原始文本**。比如 node -v 执行后打印的 v20.11.1,或者 npm install 完毕时回显的 + eslint@8.56.0 added 123 packages...——这些是合法的。samp 不接受虚构内容、API 响应体、日志文件片段,也不接受带解释性前缀的文本(如 "输出:" + JSON.stringify(data))。
多行输出不加 pre 就会变一行
samp 是内联元素,天生不保留换行符和多余空格。直接写 <samp>Line1<br>Line2</samp> 虽能换行,但语义错乱(br 不该出现在纯输出样本里);写 <samp>Line1\nLine2</samp> 则会被浏览器压成 Line1 Line2。必须用 pre 包裹:
<samp>Traceback (most recent call last):
File "main.py", line 3, in <module>
print(undefined_var)
NameError: name 'undefined_var' is not defined
</samp>
- 别用
div+white-space: pre-wrap替代pre:失去语义,屏幕阅读器无法识别这是格式化输出 - 别在
pre外再套code:变成<pre class="brush:php;toolbar:false;"><code><samp>...</samp></code></pre>,冗余且 HTML 验证可能报错 - 旧版 Safari 对
pre > samp的等宽字体继承不稳定,建议加style="font-family: monospace;"显式声明
samp 和 code、kbd 怎么分工?看谁“动了手”
同一段终端交互里,三者各司其职,混用等于语义污染:
-
kbd:用户按下的键或输入的命令,如<kbd>git commit -m "init"</kbd> -
code:可引用的代码片段,如函数名document.querySelector()、配置项package.json -
samp:系统吐出来的结果,如<samp>[main (root-commit) abc1234] init</samp>
错误示范:<samp>fetch("/api/users")</samp> —— 这是代码,不是输出;<samp>{"id":1,"name":"Alice"}</samp> —— 这是 API 响应体,该用 <pre class="brush:php;toolbar:false;"><code class="json"></code></pre> 并设 aria-label。
立即学习“前端免费学习笔记(深入)”;
样式和安全:默认不可靠,转义不能省
浏览器对 samp 的默认样式极简,有些 CSS 重置库(如老版 Normalize.css)甚至会清空它的 font-family,导致和普通文本无异。必须显式加固:
- 等宽字体栈推荐:
samp { font-family: ui-monospace, 'SFMono-Regular', 'SF Mono', Menlo, Consolas, monospace; } - 单行输出加
white-space: nowrap; overflow-x: auto;防折断 - 多行输出用
white-space: pre;或pre-wrap,取决于是否允许长行自动换行 - 服务端返回或 JS 动态插入的内容,必须先对
、<code>>、&做 HTML 实体转义,否则<samp><script>alert(1)</script></samp>会真实执行
最常被忽略的是上下文断裂:同一段文字,在教程步骤里是 samp,在接口文档里就得是 code;哪怕内容完全一样,语义变了,标签就必须换。



















