优化MathJax公式引用跳转偏移
在 Hexo + Fluid 主题里,如果你开启了 MathJax,并且在文章里用 \label / \eqref 做公式编号与引用,经常会遇到一个体验问题:点击引用跳转后,落点总是偏下,导致目标公式被顶部导航栏遮住,或者需要再往上滚一下才能看到。
这篇文章记录一次「不改主题源码、只用 Fluid 的自定义注入能力」的修复过程:让标题锚点和 MathJax 公式引用锚点都能更准确地跳转到可视位置。
现象与原因
1) 普通锚点:被 fixed navbar 遮住
Fluid 的导航栏是固定在顶部的(fixed / sticky),浏览器默认的锚点跳转会把目标元素滚到视口顶部,结果目标内容被导航栏盖住。
这种问题通常用 CSS 的 scroll-padding-top / scroll-margin-top 就能解决。
2) MathJax 公式引用:跳到了“编号单元格”,不是“公式块”
更麻烦的是 \eqref{...}:MathJax 生成的链接会指向形如:
#mjx-eqn%3Aeq%3Aeinstein2(URL 编码后)
而这个 id 通常挂在 公式右侧编号那一格(例如 <mjx-mtd id="mjx-eqn:eq:einstein2">),而不是挂在整个公式容器(<mjx-container>)上。
对于较高/多行公式,滚动到“编号单元格”的位置,视觉上就会像「跳过头」:你看到的是编号附近,而不是公式顶部。
所以仅靠 *:target { scroll-margin-top: ... } 仍可能不准,需要额外把落点校正到 对应的 <mjx-container>。
方案:CSS 统一偏移 + JS 专门修正 MathJax 锚点
实现思路:
- 用 CSS 解决大多数锚点场景(标题、手写
<a id=...>等),让浏览器原生滚动就带 offset。 - 对
mjx-eqn...这种 MathJax 锚点,监听hashchange,把滚动目标从“编号单元格”改为最近的<mjx-container>,并按导航栏高度做偏移。
1) 添加全局锚点偏移 CSS
新建文件:source/custom/scroll-offset.css
1 | |
说明:
html { scroll-padding-top }:影响浏览器对“锚点滚到顶部”的默认行为。*:target { scroll-margin-top }:对命中的目标元素额外设置上边距,兼容更多情况。
2) 添加 MathJax 锚点跳转校正 JS
新建文件:source/custom/mathjax-anchor-fix.js
核心逻辑:
- 如果 hash 以
mjx-eqn开头:找到那个id对应的元素(通常是mjx-mtd),再向上找最近的<mjx-container>,滚到它的顶部。 - 偏移量使用
#navbar的实际高度(避免你手动估算)。 - 为了应对 MathJax typeset 和字体加载造成的布局变化,短时间内重复校正几次,并在
MathJax.startup.promise完成后再跑一次。
(代码已在本仓库添加,文件名如上,不再重复贴全文。)
3) 在 Fluid 配置中注入自定义资源
编辑 _config.fluid.yml,把自定义文件加到 custom_css / custom_js:
1 | |
注意:
- 路径是相对
source/的站点根路径(例如source/custom/scroll-offset.css对应/custom/scroll-offset.css)。 - 修改
_config.fluid.yml后,通常需要重启本地预览(hexo server)。
4) 重新生成并验证
1 | |
建议用一个最小用例验证(本仓库已有类似测试文章):
1 | |
然后在正文里写:
1 | |
点击引用 (1) 后应能直接看到公式(不需要再手动往上滚)。
可调参数与排错思路
- 如果仍被遮住:把
source/custom/scroll-offset.css里的--anchor-offset调大一点。 - 如果只对
\eqref不准:打开浏览器控制台看location.hash,确认是否是#mjx-eqn...形式;如果主题或 MathJax 配置改变导致 DOM 结构变化,可以把 JS 里“找最近<mjx-container>”那段改成更贴合你页面结构的选择器。