
本文详解因 JavaScript 动态包裹连字导致嵌套 破坏 ffi/ffl 等复合连字渲染的问题,提供可靠、轻量的 DOM 修复方案,并附可直接运行的优化代码。
本文详解因 javascript 动态包裹连字导致嵌套 `` 破坏 `ffi`/`ffl` 等复合连字渲染的问题,提供可靠、轻量的 dom 修复方案,并附可直接运行的优化代码。
在使用负 letter-spacing(如 -0.08em)增强标题紧凑感时,现代字体(如 Cormorant Garamond、Georgia)的连字(ligatures)——特别是三字符组合 ffi、ffl、ffj——常意外失效。为恢复连字,开发者常采用 JS 扫描并用 <span class="glyph"></span> 包裹匹配子串,再通过 .glyph { letter-spacing: 0 } 局部解除字间距干扰。但此法存在隐蔽陷阱:多次正则替换会引发嵌套包裹。
例如,对文本 "Office" 中的 "ffi" 进行替换后,后续遍历 "fi" 时,会错误地将已包裹的 <span>ffi</span> 内部再次匹配,生成嵌套结构:
<span class="glyph">f<span class="glyph">fi</span></span>
该结构破坏了浏览器对连字字形的识别上下文——尤其在 Safari 和部分 WebKit 内核中,跨元素边界的字符无法触发 ffi 这类三连字(triple ligature),仅降级显示为 f + fi 双连字,视觉上缺失中间 f 的连笔效果。
✅ 正确解决方案:扁平化嵌套节点
核心思路是:所有替换完成后,将所有 .glyph 元素的内容“展平”为纯文本,消除嵌套层级,确保连字字符处于同一文本节点内:
function highlightText(el, substrings, classNames = "glyph") {
// 按长度降序排序,优先匹配长连字(ffi > fi),减少误覆盖
const sortedSubstrings = [...substrings].sort((a, b) => b.length - a.length);
sortedSubstrings.forEach((substring) => {
const regex = new RegExp(`(${substring})`, "gi");
el.childNodes.forEach((childNode) => {
if (childNode.nodeType === Node.TEXT_NODE && childNode.nodeValue.trim()) {
const replaced = childNode.nodeValue.replace(regex, `<span class="${classNames}">$1</span>`);
if (replaced !== childNode.nodeValue) {
childNode.parentNode.innerHTML = replaced;
}
}
});
});
// ✅ 关键修复:清除嵌套,确保连字字符在同一文本节点
el.querySelectorAll(`.${classNames}`).forEach(span => {
span.replaceWith(span.textContent); // 完全移除 span,保留纯文本
});
}
? 为什么
replaceWith(textContent)比innerHTML = innerText更优?
前者彻底删除<span></span>标签,避免残留空格或换行;后者仅重置内容,但若原<span></span>内含空白或格式,可能引入不可见干扰。
⚠️ 注意事项与最佳实践
-
匹配顺序至关重要:务必按字符串长度从长到短处理(
["ffi", "ffl", "ffj", "fi", "fl", "fj", "ff"]),否则短连字(如"fi")会提前截断长连字(如"ffi")。 -
避免
innerHTML频繁重写:当前实现适用于静态标题;若用于动态内容,建议先克隆节点、操作后再替换,防止事件丢失。 -
CSS 补充建议:为确保连字强制启用,可在
.glyph类中添加:.glyph { letter-spacing: 0; color: red; font-feature-settings: "liga" on, "clig" on; /* 显式开启标准+上下文连字 */ } -
替代方案考量:若项目支持现代 CSS,可尝试
font-variant-ligatures: common-ligatures;配合text-rendering: optimizeLegibility;,但负字间距下仍需 JS 辅助控制局部间距。
通过上述修复,<h1>Office Often Oficial Offset</h1> 中的 ffi 将稳定渲染为完整连字,同时保持整体标题的紧凑排版——兼顾设计意图与字体技术本质。










