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