html本身无版本对比能力,所有对比均依赖外部工具解析diff后用/标记并css渲染;直接渲染git diff易致xss、语义丢失及可访问性问题。

HTML 本身不提供版本对比能力,所有“对比”都是外部工具或代码解析 diff 输出后,再用 <ins></ins> / <del></del> 标记 + CSS 渲染实现的。 直接把 Git 的 diff -u 输出塞进 HTML 或用 JS 粗暴替换 +/- 行,90% 会出样式错乱、语义丢失、XSS 风险或屏幕阅读器不可读的问题。
为什么不能直接渲染 git diff 输出
Git 的 diff -u 是纯文本格式,不是 HTML。它含大量非转义字符(如 、<code>>、&),直接 innerHTML = rawDiff 会导致标签被浏览器解析、脚本执行、甚至 DOM 结构断裂。
- 常见错误现象:
<div> 被截断成 <code><di>,后续内容全乱;<code>class="btn"变成孤立属性;+++行被当 HTML 注释忽略 - 必须先做 HTML 实体转义:把
→ <code><,>→>,&→& - 再按 diff 规范逐行识别类型:
^\+(新增行)、^-(删除行)、^@@(块头)——别用^\+正则,JSON 里也可能有+"id" - 空行和缩进要保留,否则代码可读性崩坏;建议用
<pre class="brush:php;toolbar:false;"><code></code> 包裹,并设 <code>white-space: pre</code></pre> - 生成的 HTML 含内联样式(
style="background-color:#bae"),深色模式下文字可能看不见,WCAG 对比度也不达标 - 正确做法:用
make_table()获取原始行数据,自己拼<ins></ins>/<del></del>,再套一层<pre class="brush:php;toolbar:false;"><code></code>,CSS 全部外置</pre> - 如果必须用
make_file()输出,务必重写 CSS,把.diff_add改为ins选择器,并加text-decoration: underline wavy #28a745 - 常见错误现象:高亮区域里出现未闭合的
<span>、孤立的 <code>>、或整个段落样式错位 - 必须先做预处理:用
DOMParser解析 HTML,提取纯文本内容做 diff,再把变更映射回原始 DOM 节点位置 - 或者走保守路线:只对
textContent做 diff,把<ins></ins>/<del></del>插入到文本节点内部,不碰标签结构 - 若真要 diff 带标签的 HTML,推荐用
html-diff(Python)或htmldiff(PHP),它们基于lxml或 DOM 树比对,不是字符串暴力匹配 - 没设 CSS:浏览器默认不显示任何样式,
<ins></ins>和<del></del>是纯语义标签,必须手动加text-decoration或background-color - 没处理换行:它们是行内元素,包裹
<p></p>或多行文本时,会塌陷或错位;需加display: inline-block或display: block - 没考虑可访问性:仅靠颜色区分不够,色觉障碍用户无法分辨红绿;必须加图标(
aria-label="已删除")或文字提示(如「[已删除]」前缀)
difflib.HtmlDiff 生成的 HTML 怎么用才安全
Python 标准库 difflib.HtmlDiff 会输出带 <table> 的完整 HTML,但它默认不转义内容,也不适配现代语义化要求。<ul><li>它把差异塞进 <code><td class="diff_add"> 这类无语义的 class,<code><ins></ins>/<del></del> 标签一个不用,屏幕阅读器完全感知不到“这是新增还是删除”
前端用 diff-match-patch 处理 HTML 时怎么避免标签撕裂
diff-match-patch 擅长字符串级 diff,但原始 HTML 是嵌套结构。直接 diff 两段 HTML 字符串,<p>hello</p> 和 <p>hello world</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill7761" title="Article To Html"><img
src="https://img.php.cn/upload/skill/000/000/081/179168408018805.jpg" alt="Article To Html" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill7761" title="Article To Html" class="overflowclass">Article To Html</a>
<p class="overflowclass">文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。</p>
</div>
<a rel="nofollow" href="/xiazai/skill7761" title="Article To Html" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div> 的差异可能切在中间,导致 <p></p> 开头或
用 <ins></ins> / <del></del> 标记时最常漏掉的三件事
很多人写了 <ins>新内容</ins> 就以为完事了,但实际部署时经常翻车。
真正难的不是“怎么标出差异”,而是“怎么让标记既准确又健壮,还能被所有人正确理解”。字符串 diff 容易,DOM 结构 diff 才是坑。别跳过转义、别绕过语义、别假设用户只看颜色。










