导读:本期聚焦于小伙伴创作的《前端水印技术有哪些JS实现方案?如何防止用户篡改页面水印?》,敬请观看详情。把公司机密文档直接丢到网页里展示,最怕有人截图外传还查不出源头。前端水印就是在页面上铺一层隐形或显性标识,把用户ID、时间印进去。常见做法有用canvas画图转base64当背景,或者用DOM节点绝对定位覆盖。这两种都能快速上线,但有个坑:水印节点挂在body下,懂点控制台的 user 随手删掉节点或改CSS就消失了。更稳妥的思路是用MutationObserver盯住水印容器,一旦发现被删就重新生成,再把关键样式用!important锁死。下面具体拆解canvas绘制、DOM覆盖和防篡改三块实现,并给出可直接抄的代码。

在前端业务中,为了防止截图泄露后无法追溯责任人,通常会在页面上添加水印。水印既能明示文档归属,也能携带用户身份信息。实现方式主要分两类:基于canvas生成图片作为背景,以及用DOM元素覆盖在内容上。这两种方式各有适用场景,也需要配合防篡改机制才能真的起作用。

前端水印技术有哪些JS实现方案?如何防止用户篡改页面水印?

一、使用Canvas生成水印背景

Canvas方案的核心是先在一个离屏canvas上绘制文字,再调用toDataURL方法把画布转成base64图片,最后把它设为某个容器的background-image。这样做的好处是水印和页面内容不在同一个DOM层级,看起来像原生背景,不干扰交互。

下面是一段最基础的canvas水印生成代码,支持旋转和透明度设置:

function createCanvasWatermark(text) {
  var canvas = document.createElement('canvas');
  canvas.width = 240;
  canvas.height = 140;
  var ctx = canvas.getContext('2d');
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.rotate(-20 * Math.PI / 180);
  ctx.font = '14px Arial';
  ctx.fillStyle = 'rgba(0, 0, 0, 0.15)';
  ctx.fillText(text, 20, 80);
  return canvas.toDataURL('image/png');
}

var watermarkImg = createCanvasWatermark('user_123_2024');
var container = document.getElementById('content');
container.style.backgroundImage = 'url(' + watermarkImg + ')';
container.style.backgroundRepeat = 'repeat';

这种方案实现简单,性能也不错,因为背景图由浏览器渲染引擎处理,不会增加太多重排开销。但如果用户用开发者工具把container的background-image清空,水印就没了,所以单纯靠canvas背景并不安全。

另外需要注意,canvas绘制时如果包含中文,要确保字体在运行环境可用,否则可能变成方块。对于高并发渲染大量水印的场景,可以缓存生成的base64字符串,避免重复绘制。

二、DOM节点覆盖式水印

另一种思路是在页面最上层插入一个绝对定位的div,里面用很多小水印块平铺。这种方式比背景图更灵活,比如可以绑定点击事件做埋点,也方便动态更新文字。

实现时通常创建一个fixed定位的遮罩层,pointer-events设为none,这样不会挡住用户操作。代码示例如下:

function appendDomWatermark(text) {
  var mask = document.createElement('div');
  mask.id = 'wm_mask';
  mask.style.position = 'fixed';
  mask.style.top = '0';
  mask.style.left = '0';
  mask.style.width = '100%';
  mask.style.height = '100%';
  mask.style.pointerEvents = 'none';
  mask.style.zIndex = '9999';
  mask.style.backgroundImage = 'url(' + createCanvasWatermark(text) + ')';
  mask.style.backgroundRepeat = 'repeat';
  document.body.appendChild(mask);
}

appendDomWatermark('ipipp.com_user_88');

DOM覆盖的优点是结构清晰,哪里被删一眼就能看出来。不过它引入了额外节点,在低端设备上可能有轻微合成层开销。如果页面本身有很多fixed层,还要注意z-index冲突。

实践中,不少团队会把canvas生成和DOM覆盖结合:用canvas画单块水印,再用DOM平铺,兼顾了绘制效率和可维护性。

三、防止水印被篡改

前面两种方案单独用都不保险,因为打开控制台就能删节点、改样式。要解决这个问题,可以借助MutationObserver监听body或水印容器的子节点变动。

当观察到水印节点被移除,或者属性被改,就立刻重新插入。同时把关键CSS用行内style写死,减少被外层样式覆盖的可能。示例如下:

var target = document.body;
var observer = new MutationObserver(function (mutations) {
  mutations.forEach(function (m) {
    if (m.removedNodes && m.removedNodes.length) {
      for (var i = 0; i < m.removedNodes.length; i++) {
        if (m.removedNodes[i].id === 'wm_mask') {
          appendDomWatermark('ipipp.com_user_88');
        }
      }
    }
  });
});
observer.observe(target, { childList: true, subtree: true });

这段代码监听body的直接子节点删除,一旦发现wm_mask没了就补回来。如果要更严格,还可以监听属性变更,防止有人改display为none。不过MutationObserver只能增加篡改成本,无法做到绝对防护,因为用户始终能断点调试或禁用JS。

因此在安全要求高的场景,除了前端水印,还应该配合后端日志、接口鉴权等手段,让截图外传至少能定位到账号级别,而不是指望水印本身拦住所有人。

四、小结与选型建议

如果项目只是内部系统展示,用canvas背景就能满足;如果是对外文档且追责需求强,建议DOM覆盖加MutationObserver。无论哪种,都别把水印当唯一防线。

最后提醒,水印文字不要直接塞敏感信息明文,可以做个短哈希,既标识用户又不暴露手机号邮箱。这样即使截图流出,也只看到一串代号,降低二次伤害。

watermarkjavascriptcanvas修改时间:2026-08-08 22:18:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。