纯css伪元素水印防爬无效,仅具视觉提示作用;真正有效的方案是canvas动态生成带用户标识的水印,并配合mutationobserver高频检测与自动恢复机制。

纯 CSS 伪元素水印对防爬虫基本无效,它只能起到视觉提示作用;真要增加截图/录屏/复制后的溯源成本,必须用 Canvas 动态生成、带用户标识的水印,并配合 DOM 防篡改逻辑。
body::before 为什么挡不住爬虫和截图
这个方案本质只是加了一层固定定位的半透明文字,不参与 DOM 渲染流程,但完全暴露在开发者工具里。用户打开 DevTools → Elements → 找到 body::before → 右键「Delete node」或直接禁用对应 CSS 规则,水印立刻消失。截图、PDF 导出、录屏也照常进行,毫无阻力。
- 水印内容写死在 CSS 中,无法绑定当前登录用户、IP、时间戳等动态信息
-
z-index: -1或z-index: 9999都不影响截图结果——截图捕获的是最终合成帧,不是层叠顺序 - 浏览器扩展(如「Disable Styles」)一键清空所有样式,包括伪元素
- 打印预览中,
body::before默认不显示,除非显式加@media print { ... }
Canvas 水印如何嵌入动态信息
关键不在“画出来”,而在“每次加载都不同”。比如把 user.name 和 Date.now() 拼进文字,再用 Canvas 绘制为背景图,最后设给 body.style.backgroundImage。这样即使截图流传出去,也能反查是哪个账号在什么时间访问的。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- canvas 宽高至少设为
2 * window.innerWidth和2 * window.innerHeight,否则平铺时水印边缘会断裂 - 必须先
ctx.translate(canvas.width / 2, canvas.height / 2),再ctx.rotate(-30 * Math.PI / 180),否则文字绕左上角旋转,根本偏出画布 - 用
ctx.fillText(),别用ctx.strokeText():后者只有描边,高分屏下极细、打印时几乎不可见 - 生成的 data URL 很长,不要硬塞进 CSS 文件,应在 JS 中执行
document.body.style.backgroundImage = url(...)
怎么让水印更难被移除
防移除不靠加密,而靠高频检测 + 自动恢复。Canvas 水印本身可被删,但你可以监听 body 的 DOM 变化,一旦发现水印容器被删或 backgroundImage 被清空,立刻重绘。
- 用
MutationObserver监听body的attributes(检查style.backgroundImage)和childList(检查水印div是否还在) - 观察回调里不要直接重绘,加个
setTimeout(..., 100)避免触发栈溢出 - 避免只监听一个节点:攻击者可能删掉整个
body再重建,所以最好同时监控document.documentElement的 class 列表变化 - 水印文字建议含干扰字符,比如「机密|ID:U_7a2f|2026-04-16」,比单纯「机密」更难批量 OCR 识别
真正难处理的不是“怎么画水印”,而是“怎么让水印在被删后自动回来”和“怎么让截图里带上的信息能反向定位人”。这两点没做,前端水印就只是个摆设。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










