Skyphobia

CSS学习笔记(渐变色文本)

曾经在《利用 Canvas 实现网页文字颜色渐变》一文中提到过用 Canvas 解决非 webkit / blink 内核浏览器展示渐变色文字的方案。

用Canvas处理一些CSS难以解决的问题看似酷炫,实则有若干痛点(可能还不止这几点):

  • JavaScript 掺和进了样式层面,有违纯粹原则;
  • Canvas 依赖分辨率,对文本的渲染支持很差;
  • 在不支持 Canvas 的浏览器上难以回退样式。

因此在这里介绍下上次文章中提到的另一种网页文字颜色渐变的实现方案—— SVG,它可以在一定程度上解决 Canvas 的这些痛点(当然也会引入一些新的问题,下面会提到)。下面祭出我们的利器,SVG Texts & Gradients。

SVG 文本

通过 SVG 文本(SVG Texts),我们可以在 SVG 中写入文本。相较 HTML 的文本而言,它既拥有 DOM 上的可操作性,又可以通过fill/stroke属性对文本本身进行千变万化的填充,其中就包括实现文字渐变的关键:SVG 渐变(SVG Gradients)

下面的代码创建了一个font-size2rem的 SVG 文本:

看上去和普通的文本没什么区别

1
2
3
4
5
<svg xmlns="http://www.w3.org/2000/svg">
<text dy="2rem" class="hanzo">
竜が我が敵を喰らう!
</text>
</svg>
1
2
3
.hanzo {
font-size: 2rem;
}

创建出来的 SVG 文本和普通的 HTML 文本看上去并没有什么很大的差异,它同样可以被用户选择、复制或者粘贴,看起来这是一个不错的开端。

SVG 渐变

有两种类型的SVG 渐变(SVG Gradients),线性渐变和径向渐变。前者沿着直线改变颜色,后者从一个点开始发散改变颜色,分别用<linearGradient><radialGradient>来定义。
要注意的是,这里做的仅仅只是定义,如果不被其他 SVG 元素引用的话,被定义的 SVG 渐变并不会产生任何视觉上的效果。此外,虽然可以在 svg 画布上直接定义这两种渐变,但出于可读性和复用性的考虑,推荐把它们定义在<defs>内部:

1
2
3
4
5
6
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient></linearGradient>
<radialGradient></radialGradient>
</defs>
</svg>

现在我们创建了两个没有任何效果的 SVG 渐变,接下来就是见证奇迹的时刻。

线性渐变

x1x2y1y2四个属性定义了渐变路线走向,可以设置为百分比,默认水平方向。
定义在<linearGradient>内部的<stop>结点用于指定渐变的offset(偏移位置)以及stop-color颜色中值。

下面的代码创建了一个纵向红白渐变:

1
2
3
4
5
6
7
8
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient x1="0" y1="0" x2="0" y2="100%">
<stop stop-color="red" offset="10%" />
<stop stop-color="white" offset="90%" />
</linearGradient>
</defs>
</svg>

径向渐变

径向渐变的<stop>和线性渐变相似,<radialGradient>略显复杂:cxcy定义渐变中心,r定义渐变半径,fxfy定义了渐变的焦点。

下面的代码创建了一个中心扩散的红白渐变:

1
2
3
4
5
6
7
8
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
<stop stop-color="red" offset="10%" />
<stop stop-color="white" offset="90%" />
</radialGradient>
</defs>
</svg>

最终实现效果

最后在 SVG 文本上通过fill属性或者 CSS 的fill属性应用应用上之前创建的 SVG 渐变就能看到最终效果了:

最终实现效果

1
2
3
4
5
6
7
8
9
10
11
<svg xmlns="http://www.w3.org/2000/svg">
<text dy="2rem" class="hanzo">
竜が我が敵を喰らう!
</text>
<defs>
<linearGradient x2="0" y2="100%" id="red-white">
<stop stop-color="red" offset="10%" />
<stop stop-color="white" offset="90%" />
</linearGradient>
</defs>
</svg>
1
2
3
4
5
6
7
8
svg {
width: 20rem;
height: 2.5rem;
.hanzo {
font-size: 2rem;
fill: url('#red-white');
}
}

关于兼容和样式回退

通过 Can I use 可以看到 SVG 在主流浏览器中的支持程度几乎是一片绿灯的,在不关心 IE8 及以下用户的时候可以放心使用 SVG 来实现渐变色文本。

IE8以上的主流浏览器均支持SVG

至于在那些不支持 SVG 的浏览器中,我们的 SVG 文本会像过了午夜零时的灰姑娘一样失去绚丽的外表,恢复成原本黑漆漆的文字。不过这点总比只能显示原本预设好内容的 Canvas 要好,因为我们还能用 CSS 为黑漆漆的 SVG 文本(这个时候只是普通的HTML文本了)提供基础的回退样式。

最后啰嗦一句

最早在写 GSR 第四版的时候发现 Canvas 不太适合用来实现渐变色文本的问题,那个时候对 SVG 还不怎么了解。直到最近看《CSS Secrets》时意识到了 SVG 的便利性,就琢磨是时候尝试用 SVG 来替代 Canvas 实现这个效果了,毕竟用 JS 来操作这种样式实在繁琐得不行……