快捷菜单
常用功能一站直达
更多功能请点顶栏「快捷菜单」

1目前,我文章页面加载哪里是不是有Bug呀?
2
3有的小伙伴打开我网站,会看到页面抖动,抽搐
4
5但有的小伙伴打开我网站,都正常,我打开自己网站也都正常
6
7只是有个懂技术的大佬发现如下问题:
8你要给图片加占位图
9我反正没见到抽搐
10但那个抽搐,是因为图片太多,加载导致的
11悬停描边,这个有问题
12悬停移除阴影,然后从黑描边,变成蓝描边
13这不对劲
14
15其它懂代码的大佬给的建议:
16给你优化建议:让所有图片都跟占位图一样的尺寸,自适应缩放固定占位图尺寸,避免占位图加载成功,把你的长图、短图,直接影响文档篇幅,或加大或减短,就会出现这种现象
17
18请帮我深入排查并分析下。结论:是有问题,而且大佬说得基本对。 页面「抽搐」主因是图片占位尺寸和真实宽高比不一致,导致布局反复重排(CLS);悬停描边是次要的视觉问题,不是主因。
这很正常,取决于网络和缓存:
| 情况 | 表现 |
|---|---|
| 图片已在浏览器缓存 / 网速很快 | img.complete 为 true,几乎不走占位,看起来正常(你自己常是这种) |
| 冷启动、慢网、手机 4G | 先出 16:9 占位 → 再换成真实长图/短图 → 整页高度跳变 |
| 文章图多、比例差异大(如 OneImg 这种) | 累计 CLS 更明显,像「抽搐」 |
所以不是「随机 Bug」,而是条件触发的布局偏移。
render-image.htmlLines 7-7
1<span class="img-error-wrapper"><img src="{{ $src }}" ... width="800" height="450" loading="lazy" ... style="max-width: 100%; height: auto; display: block;" /></span>每张图都当成 800×450(16:9)。浏览器先按这个比例占位;真正解码后若是竖长截图或扁图,高度会突然变,正文就上下抽一下。
_img-error-placeholder.scssLines 5-8
1.img-error-placeholder {
2 ...
3 aspect-ratio: var(--img-error-aspect-ratio); /* 实际是 16 / 9 */加载流程大致是:
先占一块 16:9 高度load 完成去掉占位,按真实比例排版图片 absolute,不占流式高度长图变高 / 短图变矮 → 整页抖动页面16:9 占位真实图片

大佬说的「长图、短图直接影响文档篇幅」——就是这个。
你们首页卡片封面其实已经做对了(660×380 + 对应 aspect-ratio),文章正文这套还没跟上。
当前实现并不是改 border 宽度,而是:
box-shadow(看起来像黑边)box-shadow: none + 蓝色 outline: 2px用 outline 是刻意避免边框挤布局的,所以悬停一般不会造成正文高度 CLS。但还有问题:
transition: all 会把很多属性一起动画scale(1.02)、translateY(-2px)(_docs-layout.scss / _vitepress-enhancements.scss),和「去阴影 + 蓝描边」抢效果所以大佬觉得「悬停描边不对劲」——对,体验别扭;但页面抽搐的主因仍是图片加载重排。
| 建议 | 现状 | 判断 |
|---|---|---|
| 给图片加占位 | 已有动画占位 | 有,但比例错了 |
| 占位与真实图同尺寸 | 全站假 16:9 | 这才是 Bug 核心 |
| 悬停描边/阴影有问题 | shadow ↔ outline + 冲突 transform | 次要,建议一并收拾 |
resources 的 Width/Height 写进 <img>,占位 aspect-ratio 跟图走800×450is-loading 时 wrapper 也用该图的 aspect-ratio,加载完高度不变scale / translateYtransition 只过渡 box-shadow、outline-coloroutline(或透明边框占位),避免真 border 挤布局如果你愿意,我可以直接改主题:先修正文图片的真实比例占位 + 统一悬停样式,这是消除「有人抖、有人不抖」最有效的一步。
按计划全部优化下吧。
已按计划改完,核心是:占位跟真实比例走,悬停不再硬切阴影/缩放。
800×450
本地图读真实宽高;支持  和 ?w=&h=;可选构建期拉取远程尺寸。aspect-ratio 占位,加载前后高度不变。
未知比例:图片留在文档流(不再用假 16:9),浏览器按真实尺寸撑开一次,避免「先错后对」的二次跳动。scale / translateY 和「卸阴影 → 蓝描边」硬切;改为透明 outline 预留 + 轻阴影变色。post-cover 固定 16:9 + object-fit: cover,避免封面加载顶版面。在 user-configuration/themes/hugo-teek/params.toml 里已加:
1[images]
2
3fetchRemoteDimensions = false改成 true 后,构建时会拉取远程图真实尺寸(首构较慢,结果会缓存),CLS 能再降一档。或在 Markdown 里写:

重新构建/刷新后再看 OneImg 这类多图长文,慢网下抖动应明显减轻。需要的话我可以再帮你开 fetchRemoteDimensions 并跑一轮构建验证。
已续完,构建验证通过。断点原因和结果如下。
resources.GetRemote 拉 AVIF 时被 Hugo 安全策略拦截:failed to resolve media type。已在配置中放行:
[security.http]
mediaTypes = [’^image/avif$']
| 场景 | 结果 |
|---|---|
WebP + fetchRemoteDimensions | 写入 1228×723、has-aspect-ratio |
| AVIF 无尺寸 | 不再写假的 800×450,走客户端占位 |
AVIF + title "920x518" | 正确锁定 920 / 518 |
| OneImg 正文(31 张图) | 全部 img-error-wrapper,fake800=0,构建成功 |
当前 Hugo Extended 能拉到 AVIF,但解不出 Width/Height。因此:
fetchRemoteDimensions = true.jpg/.jpeg/.png/.gif/.webp/.tif/.tiff 做 GetRemote
fetchRemoteDimensions = true(template / user-configuration / _default)security.http.mediaTypes 含 image/avifrender-image.html:安全 try 读宽高 + 跳过无效 AVIF GetRemote临时验证目录已清理。若要给大量历史 AVIF 也在构建期锁比例,可以说一下,我可以再加批量补 title "WxH" 或独立探测脚本。
我想给大量历史 AVIF 也在构建期锁比例,帮我再加批量补 title “WxH” 和独立探测脚本吧。
已加好脚本,并跑完全量补全。
scripts/avif-dimensions.mjs:独立探测(解析 AVIF ispe)+ 批量写 title "WxH"scripts/avif-dimensions.bat:Windows 快捷入口.cache/avif-dimensions.json(已加入 .gitignore)1node scripts/avif-dimensions.mjs run # 探测 + 写入 Markdown
2
3node scripts/avif-dimensions.mjs reprobe # 重试失败项后再 apply
4
5node scripts/avif-dimensions.mjs apply # 仅按缓存补 title
6
7node scripts/avif-dimensions.mjs probe --dry-run| 项 | 数量 |
|---|---|
| 唯一 AVIF URL | 14995 |
| 已探测到尺寸 | 14919(约 99.5%) |
| 仍失败 | 76(多为外链 403 / 本站 404 失效图) |
| 已写入 Markdown | 约 1.6 万+ 引用(分两轮 apply) |
OneImg 示例已变成:

构建时 render-image.html 会读这个 title,直接锁 --img-aspect-ratio。
改的是 hugo-teek-site/content/。正式构建前请重新跑 VP 转换 / make build(或你的 hugo-teek-tools convert),让 .content-vp-converted 跟上。
剩余 76 张失败图基本是失效外链,客户端占位仍会兜底;若要清掉死链可以再说。
清掉死链吧。
已清完。先复核再删除,76 条全部仍是死链,无误删。
报告在 .cache/avif-purged.json。以后可再跑:
node scripts/avif-dimensions.mjs purge-dead
1效果:
2Administrator@DESKTOP-7GA8OTS MINGW64 /d/hugo-teek-private (master)
3$ node scripts/avif-dimensions.mjs purge-dead
4content: D:\hugo-teek-private\hugo-teek-site\content
5cache: D:\hugo-teek-private\.cache\avif-dimensions.json
6mode: purge-dead
7缓存中待确认死链: 0
8确认删除: 0,复活可探测: 0
9报告: D:\hugo-teek-private\.cache\avif-purged.json
10清理文件 0,删除图片引用 0,死链 URL 0构建前记得重新 convert,让 .content-vp-converted 同步。
已全部推送到 origin/master。
推送提交
ca5220f7 — fix(images): 消除文章图片 CLS,并批量补全 AVIF 尺寸(916 个文件)ce72a376 — docs: 同步迭代记录(图片 CLS 修复)当前分支与远程一致,工作区干净。
精选 · 友链 · 更多

One的公众号
爱折腾博客的小白