必须用包裹堆栈并配合适当css:details pre { white-space: pre; max-height: 300px; overflow-y: auto; },避免换行丢失、缩进错乱和页面撑满。

details 标签本身不支持预格式化,堆栈会丢失换行和缩进
直接把 Error.stack 字符串塞进 <details><summary>...</summary>堆栈文本</details> 里,所有换行符 \n 会被浏览器忽略,缩进全塌成一行——这不是“优雅”,是不可读。
真正可用的解法是:用 <pre class="brush:php;toolbar:false;"></pre> 包裹堆栈内容,并确保父级 <details></details> 不施加破坏排版的 CSS(比如 white-space: normal)。
- 必须用
<pre class="brush:php;toolbar:false;"></pre>,不能用<div> 或 <code><p></p> - 堆栈字符串建议先做一次
String.replace(/\t/g, ' '),避免某些环境输出制表符导致错位 - 如果堆栈来自
console.error(e)的原始输出,优先用e.stack而非e.toString(),后者不含行号和调用链
如何动态插入带堆栈的 details(React/Vanilla 都适用)
核心是保持语义结构干净:<details><summary>Error: xxx</summary><pre class="brush:php;toolbar:false;">...</pre></details>。不要把 <pre class="brush:php;toolbar:false;"></pre> 塞进 <summary></summary>,也不要在 <details></details> 上加 display: flex 类样式——这会压扁 <pre class="brush:php;toolbar:false;"></pre> 的换行行为。
示例(Vanilla):
function renderErrorDetails(error) {
const details = document.createElement('details');
const summary = document.createElement('summary');
summary.textContent = `Error: ${error.name}`;
const pre = document.createElement('pre');
pre.textContent = error.stack || String(error);
details.appendChild(summary);
details.appendChild(pre);
return details;
}
// 插入到页面某处
document.body.appendChild(renderErrorDetails(new Error('Boom')));
Chrome/Firefox/Safari 对 details+pre 的兼容性没问题,但 Safari 15.4 之前有 white-space 渲染 bug
Safari ≤15.3 会把 <pre class="brush:php;toolbar:false;"></pre> 里的连续空格渲染成单个空格,导致堆栈缩进错乱。临时修复只需一行 CSS:
details pre { white-space: pre; } —— 注意不是 pre-wrap,后者在 Safari 旧版下仍可能吞空格。
- 无需加
!important,只要这条规则权重不低于重置样式即可 - 如果项目用了 CSS-in-JS 或 Shadow DOM,需确保该样式作用域覆盖到
<pre class="brush:php;toolbar:false;"></pre> - Edge 18 及更早版本不支持
<details></details>,但已基本退出主流场景
别在 details 里放超长堆栈而不加滚动控制
一个 200 行的 stack 直接撑满视口,用户得拉半天才能看到页面其他内容。加个简单限制:
details pre { max-height: 300px; overflow-y: auto; }
- 高度值按实际 UI 区域调整,300px 是常见卡片内安全值
- 避免用
overflow: scroll,它在 macOS 上强制显示滚动条,干扰视觉 - 如果堆栈含敏感路径(如本地文件系统路径),插入前建议用正则脱敏:
.replace(/\/Users\/\w+\/.*?\.js/g, '[redacted].js')
<pre class="brush:php;toolbar:false;"></pre> 和 CSS 的配合,而不是 <details></details> 本身有多难。漏掉 white-space 或忘了 max-height,再“优雅”的结构也会在真实场景里翻车。











