添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

准备开发一个应用,需要给新用户自动生成一个默认头像,像本论坛采用 Discourse 那样,采用首字符 + 随机背景。

假如像 Discourse 那样 ImageMagick 之类的图片生成库的话,得用特定的中文字体,想到 SVG 图片是 XML 代码,很容易生成,但是文字怎么居中呢?水平 + 垂直方向都需要居中

我注意到腾讯云的控制面板就是采用 SVG 方案,不知道它是怎么实现的?

  • 这头像是服务器端还是浏览器生成的?
  • 字体是怎么选?不同系统的默认中文字体不一样
  • x=“18.5” y=“25.5” 坐标是如何计算的?我看了【徐】占 33x46,(70 - 33) / 2 = 18.3 能解释 x,但 (70 - 46) / 2 = 12,怎么解释 y?
  • 难道每一个汉字在 Pingfang SC 中都是同样长宽比?33x46
  • <svg width="70" height="70" viewBox="0 0 38 38" fill="none"
         xmlns="http://www.w3.org/2000/svg">
            <rect x="1" y="1" width="36" height="36" rx="18" fill="#3C89DD"></rect>
            <text fill="#ffffff"
                  x="18.5"
                  y="25.5"
                  font-family="PingFang SC"
                  font-size="18"
                  font-weight="500"
                  style="text-anchor: middle;"
            >徐</text>
                  

    文本的 x/y 坐标确实有点费解。

    不过这里的 width="70" height="70" 不重要(如楼上所说,改成 700 也不影响居中),关键是 viewBox="0 0 38 38",它确定了一个 38x38 的正方形(没有单位,无极放大)。

    rect 在正方形内居中画了一个直径 36 的圆。

    text 看不太懂了,汉字高大于宽,y 坐标应该更小才是。

    另外,其实 text 并不完全居中(19(38/2) 更接近居中),加一个小的同心圆就看得很清楚了:

    svg-text-x-y623×693 31.4 KB

    文本的默认 (x,y) 基准点不是左上角,而是文本的 (left, baseline),腾讯头像的文字对齐是 text-anchor: middle; 作用的结果,把这句删了,再画了几条辅助线就一目了然了:

  • 圆心的坐标 (19,19)
  • 文本 y 坐标是对齐的是默认 baseline。
  • <svg width="70" height="70" viewBox="0 0 38 38" fill="none" style="border:1px solid #cd0000;" xmlns="http://www.w3.org/2000/svg">
            <rect x="1"  y="1"  width="36" height="36" rx="18" fill="#3C89DD"></rect>
            <rect x="8"  y="8"  width="22" height="22" rx="11" style="fill:#cd0000;stroke:#cd0000;stroke-width:0.5;"></rect>
            <rect x="0"  y="0"  width="19" height="19"  style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <rect x="0"  y="19" width="19" height="19"  style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <rect x="19"  y="0" width="19" height="19"  style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <rect x="19"  y="19" width="19" height="19" style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <text fill="#ffffff"
                  x="19"
                  y="19"
                  font-family="PingFang SC"
                  font-size="18"
                  font-weight="500"
            >徐</text>
    

    比起用绝对坐标,百分比可能是更好的选择。而且如果想要垂直方向对齐,必需把 baseline 往中间推:

    svg-text-baseline-2806×661 46.1 KB
    <svg width="70" height="70" viewBox="0 0 38 38" fill="none" style="border:1px solid #cd0000;" xmlns="http://www.w3.org/2000/svg">
            <rect x="1"  y="1"  width="36" height="36" rx="18" fill="#3C89DD"></rect>
            <rect x="8"  y="8"  width="22" height="22" rx="11" style="fill:#cd0000;stroke:#cd0000;stroke-width:0.5;"></rect>
            <rect x="0"  y="0"  width="19" height="19"  style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <rect x="0"  y="19" width="19" height="19"  style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <rect x="19"  y="0" width="19" height="19"  style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <rect x="19"  y="19" width="19" height="19" style="fill:none;stroke:blue;stroke-width:0.5;"></rect>
            <text fill="#ffffff"
                  x="50%"
                  y="50%"
                  font-family="PingFang SC"
                  font-size="18"
                  font-weight="500"
                  dominant-baseline="middle" 
                  style="text-anchor: middle;"
            >徐</text>
    

    y 坐标看起来还是有点偏上,51% 可能效果会更好。

    我也是趁着这个问题自己顺便学习了一些基本的 svg 知识,总结起来主要有:

  • svg 标签的 widthheight 定义的是画布绝对大小。
  • viewBox 定义的是逻辑上的大小,也就是说它可以随画布放大缩小。所以应该以 viewBox 的大小来摆放元素。
  • text 对齐的关键因素是 baseline 和 text-anchor 属性。
  •