纯css水印易被禁用且不随滚动重绘,canvas水印通过fixed定位、高分屏适配、透明度控制和动态内容绑定实现真正防护,但禁用js时仍失效。

纯 CSS 方案(如 body::before)能快速呈现水印,但开发者工具里删一条样式就消失;真要防截图、防右键复制、防简单删除,必须用 canvas 动态绘制并设为全屏遮罩层——它不进 DOM 树,不依赖 CSS 规则,且文字不可选、不可右键保存。
为什么 background-image 水印一禁样式就失效
CSS 背景图本质是样式层,不是内容层。用户打开开发者工具 → 右键禁用 background-image 声明,或直接清空 body 的所有样式,水印立刻归零。更关键的是:
- 它不会随滚动“重绘”,长页面中只在初始视口区域有水印,中间大片空白
- 打印时默认不渲染背景图(除非显式加
@media print { background: ... }) - 截图工具(如 Windows Snipping Tool)可单独截取内容层,跳过背景
-
opacity作用于整个元素,若误设在容器上,会把正文也变透明
用 canvas 实现真正可用的全屏水印
核心是创建一个 position: fixed 的全屏 <canvas></canvas>,用 ctx.fillText() 在网格坐标反复绘制,再设 pointer-events: none 防遮挡交互。
-
canvas.width和canvas.height必须乘以window.devicePixelRatio,否则高分屏上文字发虚 - 绘制前调用
ctx.translate(x, y)再rotate(),否则旋转中心是画布左上角,文字飞出屏幕 - 文字透明度控制在
rgba(0,0,0,0.1)左右,低于 0.08 基本看不见,高于 0.15 干扰阅读 - 平铺间距建议
120px起步,太密加重 CPU 渲染负担,太疏留白明显 - 监听
resize事件重绘,但别监听scroll——fixed定位天然跟随滚动,无需额外计算
防移除不能只靠 MutationObserver
有人以为加个 MutationObserver 监听水印 DOM 被删就能“自动恢复”,实际意义有限:
- 用户禁用 JS 后 observer 完全不运行
- observer 只能响应 DOM 删除,对禁用 canvas、清空 style、覆盖 z-index 等操作无能为力
- 混淆变量名、随机 class、加
!important只是提高手动定位成本,无法阻止有经验者直接 patch 逻辑 - 真正该做的是:水印内容绑定会话 ID 或时间戳(如
"USER-7a2f-${Date.now()}"),让每次刷新水印都不同,增加批量盗图难度
Canvas 水印的硬伤在于它仍属前端渲染——只要用户禁用 JS 或用浏览器无图模式,水印就不存在。如果你的场景涉及高敏感文档(如合同、审计报告),水印只是辅助警示,关键内容还得靠服务端生成 PDF 并嵌入不可剥离的矢量水印。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











