在CSS3和SVG出现之前,我们脑海里可能会有一些酷炫的想法,因为技术的不支持一直没办法实现。但是,随着技术的发展,这些高大上的想法越来越有实现的可能。例如,我们现在有很多的方式来实现文字填充动画。
大概一年前,Sara Soueidan发表了一篇Techniques for Creating Textured Text的文章。这篇神奇的文章告诉我们如何使用一些现代web技术、包括canvas等,来实现创建纹理文字的效果。如图:
看到这个,我们就会想,能不能让里面文字填充的背景动起来?我们可以实现文字的阴影或渐变的动画?或者使用一个视频(video
)来填充文本如何?
这篇文章我将会分享如何创建图案填充的文本动画。当然,最好还要保留文本的文字选择能力,用于复制、粘贴等。
因为是高度实验性的代码,可能有大部分浏览器不支持,为了更好的体验效果请用chrome最新版浏览器来阅读该文章,谢谢。
##方法1:使用background-clip
这个方式可能是我们脑海里第一个蹦出来的想法,虽然只有WebKit内核的浏览器支持,所以要加上-webkit-
前缀。
html标签如下:
<div class="box-with-text">
Text
</div>
CSS是这样的:
.box-with-text{
background-image:url('img/1.jpg');
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
}
效果如下:
文字依然文本,所以我们可以选择和复制。其缺点是缺乏浏览器的支持。
但我们可以用CSS渐变与-webkit-前缀以除去非Webkit的浏览器的背景:
.box-with-text{
background-image:-webkit-linear-gradient(transparent, transparent),
url('img/1.jpg');
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
}
不支持的浏览器将完全忽略了整个字符串,我们能够避免完全显示的背景图像。这简单的一招将使我们能够解决非Webkit内核的浏览器,如果我们不希望显示的图像话。
如果我们要实现填充动画,CSS可以实现。但是我们CSS动画只能实现改变背景的位置和大小,不能平滑地改变颜色。效果如图
// scss
@include keyframes(stripes) {
100% {
background-position: 0 -50px;
}
}
.box-with-text{
background-image: -webkit-linear-gradient(crimson 50%, #FD0 50%);
background-repeat: repeat;
background-position: 0 0;
background-size: 100% 50px;
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
@include animation(stripes 2s linear infinite);
}
###结论
使用该技术实现:只支持WebKit内核浏览器,有限的填充文字的动画效果。
##方法2:使用SVG
SVG是一种奇妙的格式,它具有良好的浏览器支持。在SVG中,我们有三种方式来使文章填充图案:
- fill
- mask
- clip-path
我将会逐一使用这些方式来展示文字填充图案的效果。
如果你不了解SVG,建议你阅读SVG规范,或者其他SVG教程等。
html使用方法如下:
<svg viewBox="0 0 600 300">
<text text-anchor="middle" x="50%" y="50%" dy=".35em" class="text">
Text
</text>
</svg>
在它的常规文本中,我们也可以自由的复制粘帖
在SVG中添加一个简单的linearGradient标签:
<svg viewBox="0 0 600 300">
<!-- Gradient -->
<linearGradient id="gr-simple" x1="0" y1="0" x2="100%" y2="100%">
<stop stop-color="hsl(50, 100%, 70%)" offset="10%"/>
<stop stop-color="hsl(320, 100%, 50%)" offset="90%"/>
</linearGradient>
<!-- text -->
<text text-anchor="middle" x="50%" y="50%" dy=".35em" class="text">
Text
</text>
</svg>
.text {
font: 12.5em/1 Open Sans, Impact;
text-transform: uppercase;
fill: url(#gr-simple);
}
就可以实现渐变填充的效果:
想了解更多关于gradients
的知识可以阅读Joni Trythall的文章Getting Started with SVG Gradients
使用fill
来填充颜色的方式也可以直接写在text
的属性fill
上,要使用gradients
是必须定义ID,并且将之插入到url()
中。
<svg viewBox="0 0 600 300">
<text text-anchor="middle" x="50%" y="50%" dy=".35em" class="text" fill="url(#gr-simple)">
Text
</text>
</svg>
当然,你喜欢使用css的话也行。
.text {
fill: url(#gr-simple);
}
我们可以设置gradient
的字体颜色,但是我们需要使用SMIL来控制gradient
的其他属性
<!-- Gradient -->
<radialGradient id="gr-radial"
cx="50%" cy="50%" r="70%">
<!-- Animation for radius of gradient -->
<animate attributeName="r"
values="0%;150%;100%;0%"
dur="5s" repeatCount="indefinite" />
<!-- Animation for colors of stop-color -->
<stop stop-color="#FFF" offset="0">
<animate attributeName="stop-color"
values="#333;#FFF;#FFF;#333"
dur="5s" repeatCount="indefinite" />
</stop>
<stop stop-color="rgba(55,55,55,0)" offset="100%"/>
</radialGradient>
效果如下
想了解更多关于SMIL的知识可以阅读Sara Soueidan的文章A Guide to SVG Animations (SMIL)
现在我们来使用<pattern>
试试。
<pattern>
标签的代码如下:
<pattern id="p-spots" viewBox="0 0 80 80" patternUnits="userSpaceOnUse" width="60" height="60" x="5" y="5" >
<g class="g-spots">
<circle r="5" cx="10" cy="10"/>
<circle r="7" cx="30" cy="30"/>
<circle r="5" cx="50" cy="10"/>
<circle r="9" cx="70" cy="30"/>
<circle r="11" cx="50" cy="50"/>
<circle r="5" cx="10" cy="50"/>
<circle r="7" cx="30" cy="70"/>
<circle r="9" cx="70" cy="70"/>
</g>
</pattern>
这里仅定义了圆的大小和位置,样式需要在css中定义。或者使用sass:
//scss
$colors: #1D4259, #0A7373, #30BF7C, #BAF266, #EEF272;
$max: length($colors);
.g-spots circle {
@for $item from 1 through $max {
&:nth-child(#{$max}n + #{$item}){
fill: nth($colors, $item);
}
}
}
这样就会生成下面的css:
.g-spots circle:nth-child(5n + 1) {
fill: #1D4259;
}
.g-spots circle:nth-child(5n + 2) {
fill: #0A7373;
}
.g-spots circle:nth-child(5n + 3) {
fill: #30BF7C;
}
.g-spots circle:nth-child(5n + 4) {
fill: #BAF266;
}
.g-spots circle:nth-child(5n + 5) {
fill: #EEF272;
}
想了解更多有关于SVG patterns的,可以阅读MDN-SVG教程相关文章。
我是使用sass来做css的预编译的,所以可以很方便的指定动画的延时。代码如下:
// scss
$colors: #551F7A, #BA2799, #D9587A, #FFDD00, #FFF3A1;
$max: length($colors);
$time: 2s;
$time-step: $time/$max;
.g-stars polygon {
stroke-width: 0;
animation: stroke $time infinite;
@for $item from 1 through $max {
&:nth-child(#{$max}n + #{$item}){
$color: nth($colors, $item);
fill: $color;
stroke: $color;
animation-delay: -($time-step*$item);
}
}
}
@keyframes stroke {
50% {
stroke-width: 10;
}
}
// 编译后的css
// css
.g-stars polygon {
stroke-width: 0;
animation: stroke 2s infinite;
}
.g-stars polygon:nth-child(5n + 1) {
fill: #551F7A;
stroke: #551F7A;
animation-delay: -0.4s;
}
.g-stars polygon:nth-child(5n + 2) {
fill: #BA2799;
stroke: #BA2799;
animation-delay: -0.8s;
}
.g-stars polygon:nth-child(5n + 3) {
fill: #D9587A;
stroke: #D9587A;
animation-delay: -1.2s;
}
.g-stars polygon:nth-child(5n + 4) {
fill: #FFDD00;
stroke: #FFDD00;
animation-delay: -1.6s;
}
.g-stars polygon:nth-child(5n + 5) {
fill: #FFF3A1;
stroke: #FFF3A1;
animation-delay: -2s;
}
@keyframes stroke {
50% {
stroke-width: 10;
}
}
接下来我们把里面的圆圈替换成星星,并且让他放大缩小。
因为代码比较长,就不放出了,大家可以自己审查元素来查看。
当然我们也可以使用gif动画,虽然体积会比较庞大,但是可以创建出很好的效果。
pattern中用来使用图片的方法如下:
<pattern id="p-fire" viewBox="30 100 186 200" patternUnits="userSpaceOnUse" width="216" height="200" x="-70" y="35" >
<image xlink:href="/img/post/AnimateTextFills/fire.gif" width="256" height="300"/>
</pattern>
不同于background-clip
,文本文字将正确的显示在最新的浏览器。
接下来我们来谈谈stroke
,对于html来说,我们可以使用text-shadow
的方式来模拟一个类stroke
,但是这种方式很大的局限性。
如图,实现这样的效果可以使用如下代码:
.box-with-text {
text-shadow: -0px -0px 0 yellowgreen, 0px -0px 0 yellowgreen, 0px 0px 0 yellowgreen, -0px 0px 0 yellowgreen, -1px -1px 0 yellowgreen, 1px -1px 0 yellowgreen, 1px 1px 0 yellowgreen, -1px 1px 0 yellowgreen, -2px -2px 0 yellowgreen, 2px -2px 0 yellowgreen, 2px 2px 0 yellowgreen, -2px 2px 0 yellowgreen, 0 5px 15px rgba(0, 0, 0, 0.2);
font: 26vmax/.85 Open Sans, Impact;
color: #FFF;
}
用text-shadow实现起来确实非常的繁琐,而且代码相当的臃肿。
不同于HTML,stroke
是可用于SVG的所有元素,包括文本。并且除了作为线条它们也可填充渐变和图案。
对于这种类型的stroke
,我们需要把许多颜色置入到文本中,可以使用下面的方法来实现。。
<div class="demo">
<svg viewBox="0 0 600 300" class="demo6">
<symbol id="s-text">
<text text-anchor="middle" x="50%" y="50%" dy=".35em">
Text
</text>
</symbol>
<!-- 复制多个文本 -->
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
</svg>
</div>
用样式控制颜色和动画
$colors: #551F7A, #BA2799, #D9587A, #FFDD00, #FFF3A1;
$max: length($colors);
@include keyframes(stroke2) {
100% {
stroke-dashoffset: -400;
}
}
//scss
.text {
fill: none;
stroke-width: 6;
stroke-linejoin: round;
stroke-dasharray: 70 330;
stroke-dashoffset: 0;
@include animation(stroke2 6s infinite linear);
@for $item from 1 through $max {
&:nth-child(#{$max}n + #{$item}){
$color: nth($colors, $item);
stroke: $color;
@include animation-delay(#{-(1.2 * $item)}s);
}
}
}
编译出来的css就是这样:
.text {
fill: none;
stroke-width: 6;
stroke-linejoin: round;
stroke-dasharray: 70 330;
stroke-dashoffset: 0;
animation: stroke2 6s infinite linear;
}
.text:nth-child(5n + 1) {
stroke: #551F7A;
animation-delay: -1.2s;
}
.text:nth-child(5n + 2) {
stroke: #BA2799;
animation-delay: -2.4s;
}
.text:nth-child(5n + 3) {
stroke: #D9587A;
animation-delay: -3.6s;
}
.text:nth-child(5n + 4) {
stroke: #FFDD00;
animation-delay: -4.8s;
}
.text:nth-child(5n + 5) {
stroke: #FFF3A1;
animation-delay: -6s;
}
@keyframes stroke {
100% {
stroke-dashoffset: -400;
}
}
对于每一个stroke
,我们单独设置一个动画延时,所有他们的路径就不会积聚在同一个地方,而是通过在一个字母上不同的位置循环。
###结论
使用这种方法的文本可以使用CSS样式。我们也可以选择和复制的文本。另一大优势是,SVG具有非常好的浏览器的支持。因此,创建这类文本,SVG是最好的人选之一。
未完待续……