使用 svg 创建动态水印内容

查看 css+svg 效果演示

相关很牛逼的库推荐 : watermark-dom - 基于 DOM 对象实现的 BS 系统的水印

简单的实现原理

传统的动态水印都是先用 canvas 渲染上对应的文案,生成透明 png。
然后使用 ::after 或者 背景图的方式,覆盖在需要被加水印的节点上,以此来实现加水印的效果

传统的方式存在一下几个问题:

  1. 每次都要用 canvas (相对来说耗费的资源较多)
  2. 2022 年了,很容易被人打开 F12,然后删除对应的节点/对应的背景图样式(不太安全)

针对上面 2 个问题,还是有办法解决的

使用 svg 代替 canvas

使用 svg 的思路很简单,就是利用 background-image: url('svgpath.svg') 也能正常显示的特性(毕竟 svg 其实就是特殊一点的图片)。

准备一个 svg,svg 复杂的原理就不去深究了,说一下这次需要用得上的最基础的 svg 需要具备什么样的内容:

<svg xmlns="http://www.w3.org/2000/svg" width="144px" height="144px"><text x="18" y="0" fill-opacity="0.1" fill="#000" transform="translate(0,144)rotate(-45)" font-size="18">Jioho的博客</text>
</svg>
  • 宽高就限制这个水印的大小。我根据文本的长度给了 144px
  • 要想显示文本,就用到了 <text> 标签
  • x=“18” 这个的作用是基线的偏移,因为字体大小是 18px,可以粗糙的理解为单个字符 就是 18*18px 的。如果 x 轴不往下偏移 18px,那么字体会飘到上面去
  • fill-opacity="0.1" 毕竟是水印,需要给点透明度
  • fill="#000" 文本填充的颜色,纯黑+上面的 0.1 透明度
  • transform 就和 css 的transform是一样的,控制 x,y 轴的偏移和旋转角度。我的水印想做 45° 的

基础的介绍就是这样了。

看到 demo-1 就会发现静态水印就是这么简单就实现了。

动态控制 svg 的内容

这一趴需要一些前置知识,比如 css 变量、以及文字转 SVG 图像在线转换工具。

实现的整体思路也可以参考 张鑫旭 - 如何让文字作为 CSS 背景图片显示?

总的来说就是:

/* 背景图支持直接写入 svg 内容 */
background-image: url('<svg xmlns="http://www.w3.org/2000/svg" width="144px" height="144px"><text x="18" y="0" fill-opacity="0.1" fill="#000" transform="translate(0,144)rotate(-45 "font-size="18">Jioho的博客</text></svg>');/* 出于安全限制,需要对字符进行转义 */
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='144px' height='144px'%3E  %3Ctext x='18' y='0' fill-opacity='0.1' fill='%23000' transform='translate(0,144)rotate(-45)' font-size='18'%3EJioho的博客%3C/text%3E%3C/svg%3E");

data:image/svg+xml 就是用 文字转 SVG 图像在线转换工具 转换出来的

到这里,我们已经把文件类型的 svg 转换到页面上的 svg ,接下来只需要把水印的关键字 Jioho的博客 替换掉,动态水印就成功一半了

先说 css 变量,写法如下,不理解的请反复观看css 变量并背诵全文:

.watermark {--watermark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='144px' height='144px'%3E  %3Ctext x='18' y='0' fill-opacity='0.1' fill='%23000' transform='translate(0,144)rotate(-45)' font-size='18'%3EJioho的博客%3C/text%3E%3C/svg%3E");background-image: var(--watermark);/* 其余样式省略... */
}

css 变量定义成功后,那么用 js 控制 css 变量也是轻而易举了

在加上一些简单的控制,比如:

  • svg 的宽度就约等于 文字的长度 * 字体大小
  • 整个水印做下来是一个正方形,所以高度 = 宽度
  • 用到 .setProperty('--watermarksvg', watermarksvg) 为 css 变量赋值
let svgText = 'Jioho的博客'
let fontSize = 18
let svgWidth = fontSize * svgText.length
let svgHeight = svgWidth
let rotate = -45
watermarksvg = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${svgWidth}px' height='${svgHeight}px'%3E  %3Ctext  x='${fontSize}' y='0'  fill-opacity='0.1' fill='%23000' transform='translate(0,${svgHeight})rotate(${rotate})'    font-size='${fontSize}'%3E${svgText}%3C/text%3E%3C/svg%3E")`
document.querySelector('.watermark').style.setProperty('--watermarksvg', watermarksvg)

至此,动态的 svg 就实现了,svg 动态后,那作为背景的 svg 水印也就动态变化了 (具体效果可以看 demo-2)

水印事件穿透的问题

做完上面的步骤总体来看是没啥问题的,可是毕竟蒙了一层水印,一些点击事件/拖动事件穿透不下去,所以用到一个简单的属性,让水印的这一层不要拦截任何事件,全部穿透给下一层

.watermark {/* 省略其余代码... */pointer-events: none;
}

水印最重要的一趴,安全性

众所周知前端是没有秘密的。以上说的内容包括 demo-1 至 demo-4 ,打开控制台很容易就可以把水印的那一层 after 删除/把 css 就删了,所以这种水印防君子不防**

介绍另外一个很重要的 API MutationObserver

简单来说就是,监听到水印层被删除的时候,就立刻重新补上一个水印层(因为要监听 dom 的变化,所以这时候的水印就不能用 after 了,就必须来上一个 div 层做水印)

可是如果我们直接监听 .monitoring。如果这一层被直接删除他是并不会触发监听事件的,所以我们还得连带着水印+内容的父级 去监听,把监听的配置 childList 打开,监听这个 div 下子节点的变化

当监听的对象 mutationsList 出现 div 被删除了 mutationsList[0].removedNodes。并且删的就是水印层的话,直接往父级重新添加一个水印层即可

style 样式同理,不过我们要把 style 全部都写成行内样式,而且尽可能不保留 css 文件控制样式,这样就算想加样式也得修改 dom 节点上的 style 标签,这样就能触发我们的监听,从而把 style 样式重新改回去达到防篡改的目的(具体实现可以看 demo-5)

<div class="warkmask-conotainer"><!-- 水印层 --><div class="warkmask-delete monitoring" style="background-image: var(--watermarksvg);"></div><!-- 水印层 - end --><!-- 要被打码的内容 --><div class="content-box"></div>
</div>
var observer = new MutationObserver(function (mutationsList, observer) {mutationsList.forEach(item => {if (item.removedNodes.length > 0) {item.removedNodes.forEach(removeNode => {if (isMonitoring(removeNode)) {item.target.appendChild(removeNode)}})}})
})document.querySelectorAll('.monitoring').forEach(item => {observer.observe(item.parentNode, { attributes: true, childList: true, subtree: true })
})

追求更严谨水印安全性

如果上面的 svg 动态方案还是觉得不妥,建议就直接使用 watermark-dom - 基于 DOM 对象实现的 BS 系统的水印

这个库实现的思路其实和上文描述的差不多,唯一的区别就是为了防篡改,他们就连水印的内容也都是用 div 渲染的。这样就能很好的触发监听,防止篡改和删除了

并且用了 影子节点(shadow-root) 这种节点必须通过 js 创建,然后内部的样式不受外部的控制和影响

一些比较重要的样式,都用了 style="pointer-events: none !important; display: block !important" 的形式(行内样式+import,神仙来了都覆盖不了你的样式,加上 dom 节点的监听,根本删不掉这段样式,就能保证一直存在了)。不过千算万算少算了一步就是透明度和样式的问题(待会就去提个 issues)

这也侧面说明(前端没有绝对的安全),不过这个库已经把非常多的情况考虑进去了(主要是有现成的轮子)

最后

使用 svg 代替 canvas 做水印其实也是为了方便快捷,减少了 canvas 的渲染导出图片的操作,很好的利用了 svg 可以作为背景图的特性

加上 svg 转换工具,配合 css 变量已经可以实现很丰富的动态水印效果了。如果在加上 MutationObserver 的加持,安全性可以更进一步

以上都是简单的理论知识和简单的 demo,使用的话还是推荐 watermark-dom - 基于 DOM 对象实现的 BS 系统的水印

使用svg创建动态水印内容相关推荐

  1. Jsp 页面添加动态水印

    //从session 中读取需要的信息 <% javacommon.base.LoginUser user = (javacommon.base.LoginUser) session.getAt ...

  2. 页面水印添加工具【watermark-plus】,可防止手动删除水印,支持文本水印、图片水印、定制水印内容

    目录 效果图 文本水印 双列水印文本 图片水印 订制内容 可防止被手动删除 项目中效果 使用 API props 方法 兼容性 开源,持续更新中 watermark-plus 支持文本水印 支持图片水 ...

  3. android png图片动画,android图片系列 (4) - SVG动画(动态SVG 图片)

    看过之前那篇介绍静态 SVG 矢量图片的童鞋,应该时有感触的,SVG 就是给我们一个 空的不限制大小的canvas画板,然后我们使用 path 路径去绘制我们需要的图形,这就是静态的 SVG.动态 S ...

  4. php imagecopy 用法,php使用imagecopymerge()函数创建半透明水印

    使用imagecopymerge() 函数创建半透明水印,供大家参考,具体内容如下 // 加载要加水印的图像 $im = imagecreatefromjpeg('photo.jpeg'); // 首 ...

  5. 如何使用Next.js创建动态的Rick and Morty Wiki Web App

    Building web apps with dynamic APIs and server side rendering are a way to give people a great exper ...

  6. 通过反射创建动态代理对象(三)

    2019独角兽企业重金招聘Python工程师标准>>> 一.概述 传入目标对象和Advice(要执行的内容)对"通过反射创建动态代理对象(二)"进行改造(AOP框 ...

  7. 【ASP.NET Web API教程】2.3.5 用Knockout.js创建动态UI

    [ASP.NET Web API教程]2.3.5 用Knockout.js创建动态UI 原文:[ASP.NET Web API教程]2.3.5 用Knockout.js创建动态UI 注:本文是[ASP ...

  8. python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))...

    昨日内容回顾 1. 三个类 ChangeList,封装列表页面需要的所有数据.StarkConfig,生成URL和视图对应关系 + 默认配置 AdminSite,用于保存 数据库类 和 处理该类的对象 ...

  9. HTML5: 利用SVG动画动态绘制文字轮廓边框线条

    DEMO: 点击这里看效果 简要教程 这是一款很酷的html5 svg线条动态绘制文字轮廓边框动画特效.SVG路径动画在网页设计中是一项热门的技术,它允许我们绘制各种简单.精美的图标和文字.关于使用S ...

最新文章

  1. js控制使div自动适应居中
  2. boost::type_erasure模块实现类型安全的 printf的测试程序
  3. 如何为 .NET Core 3.0 中 WPF 配置依赖注入 ?
  4. 面试题:为什么局部变量不赋初始值报错
  5. MVP公益活动:编程一小时
  6. 文件上传中的临时上传路径问题
  7. Forrester报告:人工智能将取代6%的工作岗位
  8. wps嵌入字体后也不改变_冬至后的君子兰,养护方式要改变,不然过年不开花
  9. ltp︱基于ltp的无监督信息抽取模块(事件抽取/评论观点抽取)
  10. WPF 打印不显示的元素
  11. cad文件如何转pdf图纸进行标准的打印
  12. 关于输入法拼音拆分算法
  13. ArcGIS根据矢量图层范围裁剪影像
  14. oracle 更改SLA状态,Oracle EBS SLA 详解
  15. db2配置、db和dbm
  16. QT实现MP3播放器的歌词同步显示(卡拉OK功能)
  17. 安卓手机玩游戏卡顿怎么解决_安卓手机卡顿怎么办?5招教你变流畅,继续用三五年,媲美iPhone...
  18. Java如何判断字符串中包含有全角,半角符号
  19. 华为手机怎么刷android系统,怎样刷入安卓原生系统 在手机系统更新这件事上,小米华为和OPPOvivo谁更有良心...
  20. teamviewer出现商业用途的解决办法

热门文章

  1. #{}和${}的使用
  2. aspose将word转换为pdf[aspose.word.java 18.11]
  3. 文本检测算法性能对比
  4. cryptography
  5. 台式计算机耳机有杂音怎么办,电脑耳机有杂音滋滋怎么办
  6. 机器人操作系统ROS 编程开发--详细总结
  7. Latex中参考文献的写作方法
  8. 【干货】Python:load_workbook用法(持续更新)
  9. Keras Tuner自动调参工具使用入门教程
  10. 通信原理 | 波段的划分