直接用标签能保留缩进,但常见塌陷主因是HTML源码中自身带首行空格/换行、制表符宽度不一致、中文字体非等宽、CSS覆盖white-space、innerHTML注入破坏空白符,须顶格书写、用textContent注入、设white-space:pre-wrap、指定等宽中文字体栈并配overflow-x:auto。

直接用 别用 缩进问题从来不是单点故障,而是 HTML 结构、CSS 渲染、JS 注入、剪贴板行为四层叠加的结果。最容易被跳过的其实是第一层:<pre class="brush:php;toolbar:false;"></code> 标签就能保留缩进,但必须配合正确的 CSS 和内容注入方式,否则缩进会“看起来没了”或“粘贴时丢失”。</strong></p>
<H3>为什么 <code><pre class="brush:php;toolbar:false;"></code> 里缩进还是塌了</H3>
<p>常见错因不是标签没写对,而是 HTML 源码里 <code><pre class="brush:php;toolbar:false;"></code> 标签自身带了首行缩进或换行——浏览器会把那段空白也当内容渲染。比如:</p>
<pre class="brush:php;toolbar:false;"><div>
<pre class="brush:php;toolbar:false;"> .item { margin: 0; }</pre>
<p>上面的两个空格和换行会被当成文本的一部分,导致代码整体右偏。正确写法是让 <code><pre class="brush:php;toolbar:false;"></code> 内容严格顶格:</p>
<pre class="brush:php;toolbar:false;"><div><pre class="brush:php;toolbar:false;">.item { margin: 0; }</pre>
<ul><li>别依赖编辑器自动缩进 <code><pre class="brush:php;toolbar:false;"></code> 内容,手动删掉前后换行和空格</li>
<li>如果模板引擎不支持无空格插值(如 Vue 的 <code>{{ }}</code>),改用 <code>v-pre</code> 或服务端预处理</li>
<li>检查 DevTools 中 computed 的 <code>white-space</code> 值是否真是 <code>pre</code>,别被全局样式覆盖</li>
</ul>
<H3><code>white-space: pre-wrap</code> 是更实用的选择</H3>
<p>纯 <code>pre</code> 不折行,长代码横向溢出;<code>pre-line</code> 又会吃掉所有行首空格。真正兼顾缩进保留和可读性的,是 <code>pre-wrap</code>:</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20d3191a227.jpg" alt="DeepBI DHTML 页面生成器" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器">DeepBI DHTML 页面生成器</a>
<p>生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力:
- 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面;
- 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”;
- 提及位于 `apps/console/src/featur</p>
</div>
<a href="/xiazai/skill12116" title="DeepBI DHTML 页面生成器" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>
<pre class="brush:php;toolbar:false;">pre {
white-space: pre-wrap;
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, 'Microsoft YaHei Mono', monospace;
overflow-x: auto;
}</pre>
<ul>
<li>
<code>pre-wrap 保留所有 \n、\t、空格,同时允许在容器边界自然折行
overflow-x: auto,否则超长无空格字符串(如 base64)会撑破布局text-align: center,它会让整块代码居中,破坏相对缩进关系JS 动态注入代码时,
textContent 是唯一安全做法innerHTML 往 <pre class="brush:php;toolbar:false;"></code> 里塞字符串——<code>\n</code> 会被忽略,<code><</code> 可能触发 XSS,空格全被压缩。正确方式只有一条:</p>
<pre class="brush:php;toolbar:false;">const preEl = document.querySelector('pre');
preEl.textContent = `.container {\n display: flex;\n padding: 1rem;\n}`;</pre>
<ul>
<li>
<code>textContent 把字符串当纯文本,\n 和制表符原样保留
<),先用 (new DOMParser()).parseFromString(str, 'text/html').documentElement.textContent 解码<span></span> 进 <pre class="brush:php;toolbar:false;"></code>,改用 <code>highlight.js</code> 或 <code>Prism</code>,它们内部已处理好 whitespace 边界</li>
</ul>
<H3>复制代码时缩进丢失?得换用 <code>navigator.clipboard.write()</code></H3>
<p><code>navigator.clipboard.writeText()</code> 会规范化空白符,粘贴到 VS Code 或记事本时 \t 变空格、首尾空行被裁。要保留原始缩进,必须用底层 API:</p>
<pre class="brush:php;toolbar:false;">async function copyCodeWithIndent(codeString) {
try {
const blob = new Blob([codeString], { type: 'text/plain' });
await navigator.clipboard.write([
new ClipboardItem({ 'text/plain': blob })
]);
} catch (err) {
console.error('复制失败:', err);
}
}</pre>
<ul>
<li>必须传 <code>text/plain 类型的 Blob,不能用 text/html 或其他 MIME 类型codeString 必须含真实 \n 和 \t,别从 innerText 取——它会合并空白ClipboardItem,旧版本只能降级回 writeText() 并接受缩进妥协<pre class="brush:php;toolbar:false;"></pre> 标签本身有没有被源码里的换行和空格污染。


















