SVG 让动态水印更简单

2,549 阅读2分钟

需求

假设现在掘金产品给了我们一个需求,要求每个用户的掘金首页都要加上其用户名的水印

如果可以的话,希望能基于用户等级,水印显示不同的颜色

canvas 方案

可能大多数小伙伴都知道实现水印效果本身比较的简单,只需要平铺一张水印的图片即可。

这个需求难点就在于这个水印的图片是千人千面的。最大的问题就是要解决如何动态创建这个水印的图片。

对于前端来说要创建一个图片,比较容易想到的可能是用 canvas 画一个,然后用 canvas.toDataURL(),将这个图片转成 base64。再将这个 base64 塞到我们的 background-image 里面即可。

这个方案梳理一下,大概可以分为以下几个步骤。

  1. 拿到用户信息(用户名,等级)
  2. 基于用户信息 canvas 绘制水印图片
  3. canvas.toDataURL() 将图片转成 base64 格式
  4. 将 base64 塞到 background-image 然后实现水印效果

因为图片是我们用 canvas 自己画的,自然颜色大小,可以自由的操控,没有任何的问题。

SVG 方案

在线demo

用 canvas 往往是创建图片的首选,好在这个需求里面的水印元素只有文本和颜色两个。此时用 SVG 一切就显得更加的简单。

定制颜色,只需要修改 fill 属性,修改文字只需要替换 <text /> 里面的内容即可。

然而此时难点又来了,我们要怎么把这个 SVG 放到背景图片里呢?

《学习了,CSS中内联SVG图片有比Base64更好的形式》 这篇文章有对 CSS 内联 SVG 有详细的介绍。

<style>
.watermark{
  background-image: url("
  data:image/svg+xml,
  %3Csvg 
  width='100' 
  height='100' 
  xmlns='http://www.w3.org/2000/svg'
  %3E
    %3Ctext 
      y='15' 
      fill='rgba(0,150,150,0.8)' 
      transform='rotate(-30 120 0)'
    %3E 
    	I love SVG 
    %3C/text%3E
  %3C/svg%3E");
}
</style>

简单的说,只需要将一些 SVG 中的特殊符号转义一下,我就可以直接将 SVG 内联在我们的 CSS。

这样有一个很大的好处在于,我们里面的 fill 属性,以及文字的修改都是生效的。

<div aria-hidden="true" class="watermark"></div>
<style>
  .watermark{
    position: fixed;
    z-index: 999;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    /* 防止元素被触碰到 */
    pointer-events: none;
    /* 可以修改图片平铺尺寸 */
    background-size: 36% auto;
    /* 这里可以跳转颜色,旋转角度,文案 */
    background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' xmlns='http://www.w3.org/2000/svg'%3E%3Ctext y='15' fill='rgba(0,150,150,0.8)' transform='rotate(-30 120 0)'%3E掘金%3C/text%3E%3C/svg%3E");
  }
</style>

这个方案梳理一下,大概可以分为以下几个步骤。

  1. 用户信息,服务端渲染到 html 即可。

结语

可以看到如果用 SVG 我们可以直接将之前 canvas 的 5 个缓解,直接替换成一个。

并且理解成本和维护成本都显然更优。