likes
comments
collection
share

SVG奇淫巧技(六):<text>还能玩出什么新花样?

作者站长头像
站长
· 阅读数 10

我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第6篇文章。

如果你看过之前的《SVG不擅长些啥》,就应该知道SVG对于文字的处理有多拉胯,但即便如此,也不得不承认,<text>SVG中是一个很特殊的标签,首先它有自己专属的子元素<tspan><textPath>,这是什么概念呢?

SVG中能嵌套的标签有很多,但要说有自己专属的子标签,<text>可以说是独一份了,而且人家一次还有两个,你就说牛不牛吧,另外<text>是用来渲染文本的,但却需要用fill填充颜色来代替CSScolor属性,这意味着SVG压根就是把这些文字当做图形来处理的,不需要<path>的勾勒,文本即图形,就问你夸不夸张,那可以夸张到什么程度呢?

突破12px的限制

众所周知,由于浏览器的限制,通常12px是浏览器对于文本的最小渲染字号,也就是说即使你在CSS中设置了小于12px的字号,浏览器还是会显示为12px的文字,这个限制基本就是前端大厦头上漂的一朵乌云了,当然,这个限制完全可以通过浏览器的设置来解决,但想让每个用户去设置自己的浏览器来适配你的样式,这无异于天方夜谭。

不过,这对于SVG<text>来讲根本不叫事,你浏览器限制的是文本,与我<text>何干呢?

不信看图:

SVG奇淫巧技(六):<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奇淫巧技(六):<text>还能玩出什么新花样?

<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奇淫巧技(六):<text>还能玩出什么新花样?

当然,这并不是SVG的专属特性,CSS中也有很多方法可以实现这个效果,如:background-clipoverflow:hidden 的文字拼接等。

不仅仅只是文字环绕

还记得《SVG擅长些啥》中介绍的文字环绕吗?

没错,通过<text>的另一个专属子元素<textPath>可以让文字按照任何你想要的路径来排列,但是<textPath>不仅仅只对常见的文字有效,它对于任意的字符都是有效的,所以我们还可以实现如下的效果:

SVG奇淫巧技(六):<text>还能玩出什么新花样?

<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奇淫巧技(六):<text>还能玩出什么新花样?

<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 规定宽度时,文字会出现重叠挤压:

SVG奇淫巧技(六):<text>还能玩出什么新花样?

同样的,textlength 规定宽度超出SVG容器宽度时,文字会被裁剪:

SVG奇淫巧技(六):<text>还能玩出什么新花样?

再重申一下,textlength 只是在规定宽度内让浏览器自动计算字间距来占满限定宽度,如果换成手动修改lengthAdjust 也是一样的,lengthAdjust的原理与CSSletter-spacing相同。

利用switch来做多语言

虽然,<switch> 元素很少被用到,不过,当它与<text>结合时,就可以很轻松的实现多语言的展示:

SVG奇淫巧技(六):<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)requiredExtensionssystemLanguage (en-US)按照顺序进行评估,然后处理和呈现第一个评估为true的子元素。 其他子元素会被绕过不会被呈现。如果某个子元素是容器元素比如说是一个<g>元素,那么整个子树会被处理呈现或者全部绕过不呈现。

注意:属性display和属性visibility的值对switch 元素处理是不起作用的。 特别是在switch 元素的子元素上设置displaynone,对switch元素的 true/false 测试处理不起作用。

简单来说,<switch>会检测浏览器的系统语言,再与自身的子元素设置的系统语言做比对,最终浏览器会渲染第一个与系统语言匹配的子元素。

至于上面注意中所说的,并不是指<switch> 或其子元素即使设置display:none也不生效,而是说即使对子元素设置了display:none也不会影响<switch>的判断结果,也就是说即使你对为true的子元素设置了display:none,也不会导致错误的子元素被显示,只会正确的子元素也不显示而已。

当然,实现多语言切换的方式有很多,这个方案作为补充了解即可。

好了,以上就是对于<text>的简单总结,如果你还有其他的玩法,欢迎评论区补充讨论,如果这篇对你还算有帮助麻烦点个赞呗,多谢~。