SVG奇淫巧技(六):<text>还能玩出什么新花样?
我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第6篇文章。
如果你看过之前的《SVG不擅长些啥》,就应该知道SVG
对于文字的处理有多拉胯,但即便如此,也不得不承认,<text>
在SVG
中是一个很特殊的标签,首先它有自己专属的子元素<tspan>
和 <textPath>
,这是什么概念呢?
SVG
中能嵌套的标签有很多,但要说有自己专属的子标签,<text>
可以说是独一份了,而且人家一次还有两个,你就说牛不牛吧,另外<text>
是用来渲染文本的,但却需要用fill
填充颜色来代替CSS
的color
属性,这意味着SVG
压根就是把这些文字当做图形来处理的,不需要<path>
的勾勒,文本即图形,就问你夸不夸张,那可以夸张到什么程度呢?
突破12px
的限制
众所周知,由于浏览器的限制,通常12px
是浏览器对于文本的最小渲染字号,也就是说即使你在CSS
中设置了小于12px
的字号,浏览器还是会显示为12px
的文字,这个限制基本就是前端大厦头上漂的一朵乌云了,当然,这个限制完全可以通过浏览器的设置来解决,但想让每个用户去设置自己的浏览器来适配你的样式,这无异于天方夜谭。
不过,这对于SVG
的<text>
来讲根本不叫事,你浏览器限制的是文本,与我<text>
何干呢?
不信看图:
<svg width="60" height="20" viewBox="0 0 150 50">
<text x="20" y="20" font-size="12" fill="red">我可以小于12px</text>
</svg>
拼色文字
突破12px
字号只能算是<text>
的基本操作不值一提,除此之外还能开发出很多有趣的玩法,比如让<text>
与clipPath
结合,就可以轻松实现拼色文字的效果:
<svg>
<defs>
<clipPath id="clipPath">
<text x="10" y="50" style="font-size: 20px;">暗黑童话</text>
</clipPath>
</defs>
<g style="clip-path: url(#clipPath);">
<rect x="0" y="0" width="60" height="90" style="fill:#000;"/>
<rect x="60" y="0" width="60" height="90" style="fill:#cd0000;"/>
</g>
</svg>
同样的,如果背景是一张图片也可以裁切出带有纹理的文字:
当然,这并不是SVG
的专属特性,CSS
中也有很多方法可以实现这个效果,如:background-clip
或 overflow:hidden
的文字拼接等。
不仅仅只是文字环绕
还记得《SVG擅长些啥》中介绍的文字环绕吗?
没错,通过<text>
的另一个专属子元素<textPath>
可以让文字按照任何你想要的路径来排列,但是<textPath>
不仅仅只对常见的文字有效,它对于任意的字符都是有效的,所以我们还可以实现如下的效果:
<svg viewBox="-10 -10 200 200" width="200" height="200">
<defs>
<path id="flower"
d="M 10,30
A 20,20 0,0,1 50,30
A 20,20 0,0,1 90,30
Q 90,60 50,90
Q 10,60 10,30 z"/>
</defs>
<text>
<textPath href="#flower">🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺🌺</textPath>
</text>
</svg>
<text>
中的冷知识textlength
属性
textlength
这是一个并不常用的属性,它支持所有CSS
中的数值单位,其作用就是让文字占满textlength
规定的宽度,应用场景最多的应该就是标题文字,试想一下,如果是用SVG
做的异形中间填充文字时,要求文字撑满设计稿中的宽度,其中一个方法就是通过字间距来一点点设置,这当然可以,不过如果浏览器的渲染引擎愿意主动代劳的话,又何乐不为呢?
<svg width="200" height="100" viewBox="0 0 200 100">
<text x="0" y="55" font-size="20" fill="red" textLength="200px">
测试新属性
</text>
</svg>
不过,要注意的是当文字总宽度超出 textlength
规定宽度时,文字会出现重叠挤压:
同样的,textlength
规定宽度超出SVG
容器宽度时,文字会被裁剪:
再重申一下,textlength
只是在规定宽度内让浏览器自动计算字间距来占满限定宽度,如果换成手动修改lengthAdjust
也是一样的,lengthAdjust
的原理与CSS
的letter-spacing
相同。
利用switch
来做多语言
虽然,<switch>
元素很少被用到,不过,当它与<text>
结合时,就可以很轻松的实现多语言的展示:
<svg xmlns="http://www.w3.org/2000/svg">
<switch>
<g systemLanguage="en-UK">
<text x="10" y="20">UK English</text>
</g>
<g systemLanguage="en">
<text x="10" y="20">English</text>
</g>
<g systemLanguage="es">
<text x="10" y="20">Spanish</text>
</g>
<g systemLanguage="zh">
<text x="10" y="20">中文</text>
</g>
</switch>
</svg>
老规矩,看下MDN上关于<switch>
的介绍:
<switch>
元素对它的直接子元素上的requiredFeatures (en-US)
、requiredExtensions
和systemLanguage (en-US)
按照顺序进行评估,然后处理和呈现第一个评估为true
的子元素。 其他子元素会被绕过不会被呈现。如果某个子元素是容器元素比如说是一个<g>
元素,那么整个子树会被处理呈现或者全部绕过不呈现。
注意
:属性display
和属性visibility
的值对switch
元素处理是不起作用的。 特别是在switch
元素的子元素上设置display
为none
,对switch
元素的true/false
测试处理不起作用。
简单来说,<switch>
会检测浏览器的系统语言,再与自身的子元素设置的系统语言做比对,最终浏览器会渲染第一个与系统语言匹配的子元素。
至于上面注意
中所说的,并不是指<switch>
或其子元素即使设置display:none
也不生效,而是说即使对子元素设置了display:none
也不会影响<switch>
的判断结果,也就是说即使你对为true
的子元素设置了display:none
,也不会导致错误的子元素被显示,只会正确的子元素也不显示而已。
当然,实现多语言切换的方式有很多,这个方案作为补充了解即可。
好了,以上就是对于<text>
的简单总结,如果你还有其他的玩法,欢迎评论区补充讨论,如果这篇对你还算有帮助麻烦点个赞呗,多谢~。
转载自:https://juejin.cn/post/7142689103590064141