需求
假设现在掘金产品给了我们一个需求,要求每个用户的掘金首页都要加上其用户名的水印。
如果可以的话,希望能基于用户等级,水印显示不同的颜色。
canvas 方案
可能大多数小伙伴都知道实现水印效果本身比较的简单,只需要平铺一张水印的图片即可。
这个需求难点就在于这个水印的图片是千人千面的。最大的问题就是要解决如何动态创建这个水印的图片。
对于前端来说要创建一个图片,比较容易想到的可能是用 canvas 画一个,然后用 canvas.toDataURL(),将这个图片转成 base64。再将这个 base64 塞到我们的 background-image 里面即可。
这个方案梳理一下,大概可以分为以下几个步骤。
- 拿到用户信息(用户名,等级)
- 基于用户信息 canvas 绘制水印图片
canvas.toDataURL()将图片转成 base64 格式- 将 base64 塞到
background-image然后实现水印效果
因为图片是我们用 canvas 自己画的,自然颜色大小,可以自由的操控,没有任何的问题。
SVG 方案
用 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>
这个方案梳理一下,大概可以分为以下几个步骤。
- 用户信息,服务端渲染到 html 即可。
结语
可以看到如果用 SVG 我们可以直接将之前 canvas 的 5 个缓解,直接替换成一个。
并且理解成本和维护成本都显然更优。