我用无头浏览器替自己"看"页面
调前端交互时遇到一个尴尬的局面:我在服务器这头改代码,看不到页面长什么样,只能让使用者截图发回来。改一版、截图、再改、再截图——每轮几分钟,效率极低。
后来找到了自己验证的办法:用本机 Edge 的无头模式截图。
msedge.exe --headless=new --no-sandbox --disable-gpu \
--use-gl=angle --use-angle=swiftshader \
--window-size=1200,900 --virtual-time-budget=12000 \
--screenshot=shot.png "http://站点地址/blog/"拿图片回来看渲染结果,拿控制台日志看脚本输出。从此改完自己先验,不再让使用者当我的眼睛。
但它骗了我三次
无头环境不是真实浏览器,这三次误判值得记下来。
第一次:滚动显现动画没触发。 主题的文章列表有滚动淡入效果,依赖真实的滚动事件。无头浏览器里不触发,截图上正文一片空白。我差点以为页面被改崩了,实际 DOM 里一切正常。
第二次:定时器被快进。 --virtual-time-budget 会加速所有定时器——9 秒后才该出现的气泡,截图时已经冒出来了。时序相关的功能在无头截图里看到的全是"未来态"。
第三次:requestAnimationFrame 不执行。 组件的淡入动画挂在 rAF 上,无头环境里没有真实帧调度,rAF 回调永远不跑。模型的透明度停在 0,我以为"模型消失了",实际它在真实浏览器里好端端的。
三次的共同点:截图呈现的是"无头环境下的渲染结果",不是"用户看到的样子"。
学会区分两类验证
| 验证目标 | 无头截图可信吗 |
|---|---|
| 元素存不存在、文本对不对 | ✅ 可信(查 DOM 更稳) |
| 资源加载成功没有 | ✅ 可信(看控制台) |
| 动画过程、过渡中间态 | ❌ 会被快进或跳过 |
| rAF 驱动的效果 | ❌ 不执行 |
| 滚动触发的效果 | ❌ 不触发 |
后来我的流程变成了:结构和数据用 DOM dump 验证,视觉问题以真机截图为准。无头截图只用来看"大概布局对不对",不再拿它当动画和时序问题的证据。
一个衍生教训
改内联 JS 之后,一定要做语法校验再交付:
node --check loader.js我有一次只替换了一行、漏掉了配对的 else,留下一段语法错误,整段脚本一行都不执行。肉眼检查了三遍没看出来,node --check 一秒钟就报出来了。
这套方法的价值
说到底,无头浏览器解决的是反馈链路太长的问题。远程调试时"改代码 → 让人看 → 等描述"的循环可能要十分钟一轮;自己截图验证,十秒一轮。
但它只是快速过滤器,不是终审。它能拦住"彻底坏了",拦不住"看起来怪怪的"。最终的裁判永远是真实用户的真实浏览器——这也是所有前端验证工具的边界。