前端开发者学堂 - fedev.cn

CSS vs. SVG:图形文本的效果

发布于 大漠

这篇文章是探索有关于CSS和SVG技术的系列文章第一篇,通过例子来阐述CSS和SVG相关技术的比较。因为大家对SVG有一定的偏见,这个系列文章只是为了证明SVG解决Web上的某些设计问题。因为它是自然图像。但从客观的角度来看,我们要考虑每个技术的利弊,找出何时何地使用CSS或SVG更好。

在这篇文章中,我们将复习一些使用CSS或SVG创建图形文本的技术和相关影响。

CSS创建的图形文本

老的CSS方法

几年前,我们要在网页上创建吸引人的文本视觉效果,需要通过图像替换文本的方案,否则是无法实现想要的图形文本。

这是显示图像文本的概念,文本在屏幕上可能显示出较好的一个效果。当我们没有实现它的时候,屏幕上就会显示文本,这个效果也不错。我们把实现它的技术称为图像替换文本技术。

假设你想在<h1>标题上通过吸引人注意力的图像来显示相同的文本,你会使用类似下面的CSS:

h1.hide-text {
    text-indent: 100%;
    white-space: nowrap;
    overflow: hidden;
    background-image: url(…);
}

通过文本缩进确保标题的内容超过自己的边界溢出,并且通过overflow:hidden将溢出的文本隐藏起来,保证溢出的标题文本不显示出来。所以你最终看到的矩形区域(<h1>)内没有文本显示。

然后标题区域将显示出你在图形编辑器(例如Photoshop)创建的图形文本。

所以,显示在屏幕上标题矩形区域,里面没有文本内容,通过背景图像显示图形文本。所以你需要做的是制作效果不错的图形文本。

自从Kellum提出这个方案后没有更好的解决方案提供给开发人员使用,所以把上面的这种方法称为Kellum方法。事实上,有不少图像替代文本技术,但是Kellum方法取代了他们中的大多数方法,因为它是“最好”的选项。

这种技术是一种Hack手段,致使用户不能选择文本(因为它是运用在背景中的图形文本),接下来介绍的新的属性可以达到类似的效果,并且不需要使用图像替换文本技术。

新的CSS方法

@Lucas Bebber在Dreamweaver的博客中写了一篇《squiggly text effects》文章,有很多创建图形文本的效果,包括一些弯弯曲曲的文本效果。最常见的文本效果是纹理填充的文本效果或简单的纹理混合文本的效果,看起来像是一张背景图像。

纹理填充文本

纹理填充文本

使用CSS的background-clip属性,可以将背景图像填充到文本。这个属性决定了元素的背景区域,其默认值是border-box,背景会延伸到元素的边框边界,但可以将其值设置为padding-box content-box,将背景延伸到内距边界或内容边界。

在Webkit内核中对background-clip有一个扩展值,那就是text,使用背景根据文本进行裁剪。然后通过Webkit给文本自定的私有属性-webkit-text-fill-color,并且设置其值为transparent,背景图像就会显示在文本中,从而完成了剪切效果。

例如,将一个元素的背景图像在其文本内显示,可以给元素定义一个类名,然后运用这些样式:

.clippedElement {
  	/* background image that will serve as text fill */
  	background: url(path/to/your/image.jpg) no-repeat center center;
    /* -webkit-background-clip clips the background of the element to the text */
    -webkit-text-fill-color: transparent; /* overrides the white text color in webkit browsers */
    -webkit-background-clip: text;

  	/* general styles */
    background-size: 100% auto;
    color: #fff;
    text-align: center;
    padding: 2em;
}

正如你看到的,属性前面使用的前缀,你就不难发现,这个效果只有在Webkit内核的浏览器才能看到效果,而在Firefox和IE浏览器中是看不到效果的。

回到前面所说的<h1>标题上,给他设置一个背景,在页面上就可以不需要隐藏文本也能看到文本填充效果。还有一个替代方案,将标题放在一个div内,并且把需要填充到文本的图像设置为这个div的背景图像,使用上面的CSS样式就能实现图像文本。

下面这个示例演示的技术,确保你在Chrome、Safari和Opera浏览器都能看到效果:

对于不支持的浏览器,你可以看到一个简单的效果,就是文本的图像之上,只要你确保文本与背景图像的颜色有区别,就不会引起任何阅读上的问题。

注意,背景图像可以是任何图像,包括CSS的渐变,因为CSS的渐变也是一个背景图像。你可以从这里了解CSS渐变所有知识点

纹理填充文本(使用CSS混合模式)

接下来,我们将使用CSS的mask技术创建下图的文本效果,文本看上去有一部被抹掉了:

纹理填充文本

当使用CSS的mask时,图像文本是带了一个蒙板,而不是图像的形状(或被剪切的形状)。

上面显示的效果使用了图片来做蒙板,一年前我在Codrops上写过一篇有关于这方面的文章。图像做为一个蒙板,将文本区域下的背景展示出来。如果选择合适的蒙板图片与背景,可以得到一个无缝融合的效果。我们使用了一张油漆四溅的图像做为蒙板。为了简单起见,其自身不做任何的图层混合模式处理,只将纹理应用到文本上。

纹理填充文本

蒙板图像可以是任何你想要的图像,包括渐变做的渐变效果。

当你把CSS的mask运用到文本上或任何其他的内容时,黑色区域的文本是可见的,蒙板图像透明部分的文本是不会显示。这是因为蒙板图像在CSS中使用时,默认是一个透明通道,而不是一个亮度蒙板,这样就造成了蒙板黑色区域的文本显示出来。

对于渐变做为蒙板图像的情况时,是从黑色过渡到透明。例如,蒙板元素将是完全不透明的黑色,逐渐变得半透明,然后慢慢的变得透明。

使用CSS的mask-image将蒙板图像用在适当的文本之上:

h1 {
    /* the line that applies the splatter effect */
    mask-image: url(../img/splatter-mask_1.png); 

    /* any general styles go here like font family, alignment, etc. */
}

在写这篇文章之时,CSS的mask属性支持度不是很好。Firefox浏览器只支持SVG的蒙板,而Webkit浏览器需要添加浏览器的私有前缀-webkit。有关于mask属性的浏览器兼容性,可以查看下表:

这是另一种实现纹理文本的方法,但也是不可靠。下面这个示例演示了这个效果,请使用Webkit内核浏览器查看:

如果你想使用渐变做为蒙板图像,可以使用下面的代码替换mask-image的值:

mask-image: linear-gradient(black, transparent);

这样能看到一个文本淡出的效果。这就是如何在一个元素或文本上使用CSS实现纹理的方法。随着SVG的出现,我们或许可以找到更好的方案。

使用SVG实现图像文本

SVG太棒了。(我不得不这么说。)现在,为了简单起见,我们将使用代码来解释这一切。

在使用SVG时,文本和效果都将定义在一个<svg>元素内。

纹理填充文本

制作一个带纹理的文本,首要的就是先定认一个纹理,然后选择你喜欢的颜色填充到元素上。在我们的案例中,SVG是一段文本。

对于本例,我们将定义一个线性渐变,并将其运用到一个文本上。

纹理填充文本

代码看起来像这样:

<svg xmlns=“http://www.w3.org/2000/svg”  viewBox=“0 0 1250 400” width=“1250” height=“400”> 
    <title>Gradient-filled Text</title>
    <!— Source: http://lea.verou.me/2012/05/text-masking-the-standards-way/ —>
    <defs>
       <linearGradient id=“filler” x=“0%” y=“100%”>
           <stop stop-color=“gold” offset=“0%”></stop>
             <stop stop-color=“purple” offset=“20%”></stop>
           <stop stop-color=“deepPink” offset=“40%”></stop>
           <stop stop-color=“orange” offset=“60%”></stop>
           <stop stop-color=“yellow” offset=“80%”></stop>
           <stop stop-color=“skyblue” offset=“100%”></stop>
      </linearGradient>
    </defs>
    <text x=“100” y=“70%” font-size=“205” fill=“url(#filler)”> Radiant Text</text>
</svg>

**注意:**我们给svg指定了一个高度和宽度,但是为了确保svg是弹性的,可以使用CSS的百分比做为单位来覆盖默认的尺寸。如果你感兴趣,可以点击这里学习如何实现响应式设计的SVG。

在这个示例中使用linearGradient<def>元素定义需要的纹理,同时给这个渐变linearGradient设置一个#id,然后通过fill属性将渐变纹理用在<text>元素上。这样是不是更具语义呢?

这是上面代码的效果:

纹理可以是任何东西,哪怕是SVG的<image>元素引用的外部图像(JPEG、PNG和GIF图像等)。它也可以是一个SVG的<pattern>元素。

因为SVG是一个图形,为了方便屏幕阅读器能读到,一定要给其定义一个title<svg>中的这个title就相当于<img>元素的alt属性。

背景纹理填充文本(使用混合模式)

类似前面的技术,将CSS的mask和SVG的<def>结合起来,可以将纹理填充到SVG的<text>元素上。在填充之前,首先要做的是定义一个纹理。在SVG中可以使用<mask>定义纹理,并且在<text>元素上使用mask属性替代fill属性,将<mask>定义的纹理填充到文本中。

在下面这个示例中,我们制作了一个类似于被咬过的文本效果,如下图所示:

纹理填充文本

使用SVG制作一个咬痕的纹理,并且应用到一个文本之上。

首先通过图形编辑器制作一个咬痕的纹理,为了达到需要的效果,先在文本上添加需要的效果。它助于你在想要的地方得到你需要的效果。

然后,将图形导出成SVG,并且将图形的蒙板放在<def>元素内,导出的代码如下所示:

<svg viewBox=“0 0 900 400”>
  <defs>
    <mask id=“mask”>
      <rect x=“0” y=“0” width=“100%” height=“100%” fill=“#fff”></rect>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…”></path>
            <path fill=“#000” d=“…“></path>
            <path fill=“#000” d=“…“></path>
    </mask>
  </defs>

  <text font-size=“230” fill=“#FF481E” mask=“url(#mask)”>
    <tspan x=“0” y=“150”>nom</tspan>
    <tspan y=“280” x=“150”>nom<tspan>
    <tspan y=“400” x=“350”>nom<tspan>
  </text>
</svg>

有一点需要特别的注意:**在SVG中不像CSS的,蒙板元素需要填充白色,而不是黑色。**黑色和白色之间的任何值都将呈现为半透明状态,如此一来,元素越接白色(#ffffff),蒙板越不透明,蒙板的颜色越接近黑色(#000000),越接近透明。

因此,在上面的例子中,给咬过的形状填充为黑色,而整个SVG元素填充的是白色,这是为了确保文本在画布的任何地方都可以显示,除了黑色的咬痕之处不显示。

上面的示例代码,在浏览器上的效果看起来像这样:

这里你要做的仅是在SVG中将需要的纹理填充到文本上。你可以使用一个渐变、图像或其他任何形状或模式来填充你的文本。在<def>元素上你有很多的选择项,也可以创建很多有趣的效果,比如动画纹理填充。

使用SVG制作动画纹理填充

SVG不仅为我们提供更好的支持和模块化(因为文本和其效果都包装在一起),而且SVG还可以实现动画效果。

在SVG的<def>元素内,你可以给其定义一个填充(fill)时,也可以使用动画填充。这意味着,你将可以实现类似下图的一些动画纹理填充文本的效果:

纹理填充文本

在上面的示例中,有一个是使用了GIF动画图片做的填充,所以在文本的填充里也保持了GIF动画效果。

Codrops我写过一篇文章,主要阐述的就是如何使用SVG给文本创建动画纹理,如果你想了解更多的细节,可以仔细阅读这篇文章

总结

直到浏览器全面支持CSS的background-clip:text属性之前,SVG绝对是创建纹理填充文本效果的最佳方法。

事实上,我个人仍然喜欢使用SVG创建动画,虽然CSS中有更好的动画功能。我喜欢这个的原因是,SVG可以将文本和效果封装为一个图形,这样可以复制,也可以降级处理,更可以重用。更为重要的是,SVG的更具可读性,更具语义,也可以完全选择。

请持续关注CSS和SVG技术的比较,在下一篇文章中将继续为大家阐述相关的技术,通过这些示例的比较,更好的帮助大家做出更好的选择,决定选择哪一种技术。

本文根据@Sara Soueidan的《CSS vs. SVG: Graphical Text Effects》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://blogs.adobe.com/dreamweaver/2015/07/css-vs-svg-graphical-text.html