玩命加载中 . . .

Hexo悬挂喵修复:全站不显示与超出页面底部的排查与修复


在《Hexo博客优化教程:图库防盗链、回到顶部、悬挂喵功能修复》里,悬挂喵被改成内联脚本 + #szg-cat 的写法。之后又冒出两个新问题:全站都看不到这只喵,而且它一旦出现就会顶出页面底部。这篇把排查过程和最终修复记下来。


一、问题现象

  1. 每个页面右侧都看不到喵,但查看页面源码,<div id="szg-cat"> 确实在。
  2. 从开发者工具里复制出来的元素长这样(top 是滚动后被 JS 改过的值):
1
<div id="szg-cat" style="cursor: pointer; position: fixed; right: 80px; top: 0px; z-index: 9999; width: 70px; height: 900px; background: url(&quot;/medias/images/scroll.gif&quot;) no-repeat; transition: all 0.5s ease-in-out 0s; opacity: 1;"></div>

height: 900px 加上 top: 0px,窗口高度不足 900px 时,底部自然就挤出屏幕了。


二、排查过程

1. 先确认元素是从哪来的

全仓库只有一处定义:

1
2
3
4
grep -rn "szg-cat" --include="*.ejs" --include="*.html" \
--exclude-dir=node_modules --exclude-dir=public .

# themes/hexo-theme-matery/layout/layout.ejs:379

layout.ejs 是主题外壳,第 19 行就是 <%- body %>,所有页面都从它出。也就是说这不是”某些页面漏了”,而是所有页面都没有。

2. 实测元素的实际尺寸

本地起一个静态服务器(绝对路径 /medias/... 在 file:// 下会解析到文件系统根目录,所以必须用 http):

1
cd public && python3 -m http.server 8123

再用无头浏览器取计算样式:

1
2
3
4
5
const el = document.getElementById('szg-cat');
const cs = getComputedStyle(el);
const r = el.getBoundingClientRect();
`vh=${innerHeight} h=${cs.height} opacity=${cs.opacity} top=${r.top} bottom=${r.bottom}`;
// => "vh=600 h=0px opacity=0 top=600 bottom=600"

高度是 0px。元素在 DOM 里,但没有任何尺寸,而且是透明的。

3. 为什么高度会是 0

#szg-cat 是个空 div,喵是它的 CSS 背景图。背景图不参与布局计算,空 div 的 height: auto 就是 0;背景永远画不出来。当时那份代码还额外写了 opacity: 0,要滚动超过 300px 才把它设成 1,于是短页面连触发机会都没有。

4. 那个 900px 是从哪来的

1
2
3
sips -g pixelWidth -g pixelHeight public/medias/images/scroll.gif
# pixelWidth: 70
# pixelHeight: 900

背景图本身就是 70×900。再看它外链的 szgotop.css:

1
2
.back-to-top { /* ... */ height: 900px; /* ... */ }
@media (max-width:1000px) { .back-to-top { display:none !important; } }

固定 900px 高,而且窗口宽度小于 1000px 时整个隐藏。对比一下 git 里的版本:

1
2
3
4
5
git show HEAD:themes/hexo-theme-matery/layout/layout.ejs | grep szg-cat

# <div id="szg-cat" style="cursor:pointer; position:fixed; right:80px; top:-200px;
# z-index:9999; width:70px; height:900px; background:url(/medias/images/scroll.gif)
# no-repeat; transition:all .5s ease-in-out; opacity:1;"></div>

HEAD(也就是 CI 构建用的那版)是 top:-200px; height:900px,没有任何视口上限。滚动后 JS 把 top 改成 0,900px 的盒子就直接顶出视口底部。


三、原因归纳

现象 原因
全站都不显示 空 div + height:auto → 计算高度 0px;再叠加 opacity:0 + 滚动 300px 才显示
会超出页面底部 定位和高度写死 900px(沿用 szgotop.css 的值),没有视口上限;小于 1000px 宽时又被 CSS 整个隐藏

两个问题互相掩盖:一份代码里是”看得见但越界”,另一份是”不越界但根本看不见”。


四、修复

修改文件:themes/hexo-theme-matery/layout/layout.ejs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 悬挂的喵 -->
<link rel="stylesheet" type="text/css" href="https://blog-static.cnblogs.com/files/fsh001/szgotop.css" />
<div id="szg-cat" style="cursor:pointer; position:fixed; right:80px; top:0; z-index:9999; width:70px; height:900px; max-height:calc(100vh - 20px); background:url(/medias/images/scroll.gif) no-repeat center top; background-size:contain; transition:all .5s ease-in-out; opacity:1;"></div>
<script>
(function(){
var cat = document.getElementById('szg-cat');
if (!cat) return;
// 原图 70x900:按视口高度等比缩放,底边不会超出页面底部
function fitCat() {
var limit = window.innerHeight - 20;
cat.style.height = Math.min(900, limit > 0 ? limit : 900) + 'px';
}
fitCat();
window.addEventListener('resize', fitCat);
cat.addEventListener('click', function() {
window.scrollTo({top: 0, behavior: 'smooth'});
});
})();
</script>

关键点:

  • height:900px 保留一个基准值,空 div 必须有高度才能画出背景;max-height:calc(100vh - 20px) 让 CSS 层先把底边兜住,即使 JS 没跑也不会越界。
  • background-size:contain 让整张 70×900 等比缩进盒子,喵画在这张图的底端,所以始终完整可见。
  • top:0 + center top 保持”从页面顶端垂下来”的观感。
  • JS 里的 fitCat() 按 window.innerHeight - 20 重算高度并监听 resize,双保险。
  • 去掉”滚动 300px 才显示”,opacity:1 直接可见;点击仍然回到顶部。

五、验证

1
2
npx hexo generate
# INFO 216 files generated in 781 ms

600px 视口下重新实测同一个元素:

1
vh=600 h=580px w=70px opacity=1 bgSize=contain top=0 bottom=580 越界=NO
验证项 结果
站点生成 216 个文件
带新版标记的页面 212 / 220
600px 视口实测 高 580px,底边 580,不越界
首页 / 归档 / 分类 / 文章页抽检 均含新版

六、这些页面仍然不会有喵

页面 原因
box/index.html、box/404.html、box/cn/about.html、box/en/about.html 拷贝进来的第三方项目,是 source/ 里的独立 HTML
live2d-w/demo/demo.html、live2d-w/demo/login.html 看板娘 demo 页
search/lyb.html front-matter 里写了 layout: "false",故意不走主题布局
jichou/index.html 记仇表情包生成器,独立 HTML

这些页面不经过主题的 layout.ejs,所以拿不到这个浮层。要在这些页面上也挂喵,得把同一段 div + script 直接写进对应文件里。


七、上线注意

  1. 改的是主题源码,必须重新生成并部署才会生效(hexo clean && hexo g && hexo d,或等 CI 构建);CI 构建的是仓库里的提交内容,别忘了 git push。
  2. 仓库根目录还留着一份更早的构建产物(index.html、archives/ 等),用的是旧的 .back-to-top 类写法;而 .github/workflows/deploy.yml 是把仓库根目录整包当站点上传的。如果那份 Pages 也在提供访问,它不会跟着更新,建议把上传路径改成 public。
  3. szgotop.css 现在已无实际用途(新构建里 back-to-top / cd-top 出现 0 次),可以删掉那个外链,少一个外部依赖。

附:本地复现与验证步骤

1
2
3
4
5
# 1. 起静态服务器(必须在 public 目录下,用 http 而不是 file://)
cd "博客目录/public" && python3 -m http.server 8123

# 2. 浏览器打开 http://127.0.0.1:8123/index.html
# 在控制台执行,看元素到底有没有尺寸
1
2
3
4
const el = document.getElementById('szg-cat');
const cs = getComputedStyle(el);
const r = el.getBoundingClientRect();
console.log(`vh=${innerHeight} h=${cs.height} opacity=${cs.opacity} top=${r.top} bottom=${r.bottom}`);

只要 h 不是 0、opacity 是 1、bottom 不超过 innerHeight,就说明喵既显示出来了,也没有跑出页面底部。


赏
留言互动
Powered by Twikoo
评论互动
- 条评论
 Previous
Hexo-Matery导航栏Logo不显示修复教程 Hexo-Matery导航栏Logo不显示修复教程
解决 Hexo-Matery 主题导航栏 Logo 加载不出来(404)的问题:去掉模板中拼接的 jsDelivr CDN 前缀,改为直接使用本地路径,并更换 Logo 图片。
2026-10-19
Next 
Taro 微信小程序完整搭建与部署教程 Taro 微信小程序完整搭建与部署教程
从零开始使用 Taro 4.x + React 18 搭建微信小程序的完整教程,包含环境准备、项目创建、页面开发、打包构建、小程序配置、微信开发者工具部署。
2026-05-08
  TOC
过节
福到
小程序