最轻量方案是手写或后端注入带语义类名(如diff-added/diff-removed)的块,配合css设置背景色;行号用::before生成;大段unchanged区域折叠需js控制max-height;嵌入git diff须服务端转义并解析为json,前端用textcontent安全渲染;行跳转需绑定data-file与data-line,按目标平台拼接锚点url。

怎么用 HTML + CSS 实现基础的代码差异(diff)展示
纯 HTML 无法自动计算差异,但可以静态呈现 diff 结构。关键不是“生成 diff”,而是“正确标记 added/removed/unchanged 行”,让浏览器能渲染出类似 GitHub PR 页面的效果。
最轻量的做法是手写或后端注入带 class 的 <pre class="brush:php;toolbar:false;"></pre> 块,用 class="diff-added"、class="diff-removed" 等语义化类名控制样式:
+ <button onclick="handleClick()">Submit</button> - <button onclick="submit()">Submit</button>
然后配简单 CSS:
.diff-added { background: #d4edda; color: #155724; }
.diff-removed { background: #f8d7da; color: #721c24; }
- 不要用
<table> 模拟左右对比——可访问性差、缩放错位、移动端崩塌<li>行号建议用 <code>::before伪元素生成,避免污染 HTML 内容结构 - 如果要支持折叠大段 unchanged 区域,必须加 JS 控制
max-height和overflow,纯 CSS 无解 - 服务端(如 Node.js/Python)用
diff库(如diff-match-patch或diffnpm 包)解析原始 diff 字符串,转成带 type(add/remove/context)和 lines 的 JSON - 前端用 JS 渲染该 JSON:对每行调用
document.createTextNode()插入,再用textContent替代innerHTML避免 XSS - 若需语法高亮,用
highlight.js的highlightElement()处理每个<code>块,别全局初始化——否则会误高亮 diff 符号(+/-) - 复制代码时混入
+/-符号和行号,用户实际要的是干净源码 - 移动端横向滚动卡顿——
table强制撑宽,哪怕内容只有 20 字符 - 如果你只审查 HTML/JS/CSS 文件,
diff2html的通用性反而成了负担;精简版只需处理三类行,100 行内 JS 就够
如何嵌入真实 diff 数据(比如 git diff 输出)
直接把 git diff 命令输出塞进 HTML 是危险的:含特殊字符(、<code>&)、无转义会破坏 DOM,且缺少行号和语法高亮。
安全做法分两步:
为什么不用现成的 diff 库(如 diff2html)却还要自己控制渲染
diff2html 默认输出是完整 HTML 字符串,直接 innerHTML = result 有风险;它生成的 DOM 结构嵌套深(<div><table><tbody><tr>…),导致:<ul>
<li>无法用 CSS 精确控制单行背景色(<code>tr 高度受字体行高影响,hover 时跳动)
审查页面里「点击行跳转到源码」怎么实现
这个功能依赖源码文件路径和行号映射。HTML 本身不提供文件系统访问,所以必须提前约定好 URL 规则,比如:
- 审查页 URL 是
/review/PR-123,对应源码在https://github.com/org/repo/blob/main/src/index.html - 每行 diff 数据附带
old_line和new_line字段,渲染时给<span class="line-num"></span>加data-line="42"和data-file="src/index.html" - 点击后拼接跳转链接:
https://github.com/org/repo/blob/main/ + data-file + "#L" + data-line - 注意:GitHub 只认
#L42,不是#42;GitLab 是#L42-45(范围),别写死
如果源码不在 GitHub/GitLab,而是内部 Git 服务器,URL 模板就得动态配置,不能硬编码在 HTML 里。
真正麻烦的从来不是渲染 diff,而是让每一行都能精准锚定到真实仓库位置——路径映射错一行,审查就失去意义。











