阅读 589

SVG 咋用?

在开发过程中,我们免不了会使用图片等素材来引导用户操作,或优化我们产品的体验。我们常用的图片格式有 SVG/PNG/JPG/JPEG/WebP 等,但由于资源加载、图片大小、缩放是否失真以及使用便捷性, SVG 已经成为了当下前端开发的宠儿🍼

“沉舟侧畔千帆过,病树前头万木春”,前端发展到现在,IconFont 似乎成为了一个当下还算不错的解决方案,我们可以像操作字体一样使用 color/font-size 等样式来控制我们想要的 icon 颜色及大小,同时缩放不会失真的矢量图特性以及较小的文件大小也为其锦上添fā🌻

但我们平时的 SVG 素材都是 UX 给我们导出,或者直接从各种 UI 库中导入的,这当然能满足我们大部分的需求,要知道 Zeplin/Figma 这些工具导出的 icon 实现都是固定的,比如我们要一个矩形 icon,实现方式可能有很多种,但这些工具导出的内容有且只有一种,这就难免会遇到一些尴尬的场景。

不得不手撸🤷‍♀️

在我们小程序的个人中心页面中有一个发票的 icon,在开发者工具上正常显示的它,在真机上却“伤心地模糊”了,并且只在 iOS 上才会模糊(就NM离谱),如下:

模糊.png

因为截图原因,所以第一个订单 icon 显得有些模糊,但相比之下大家应该可以发现第二个发票 icon 中间的两个横杠模糊地更加明显!原本以为是切图原因的我又反复切了好次,发现并没什么卵用,于是乎~不得不看一眼 SVG 实现,然后发现了一个神奇的东西 <mask>🧙‍♀️自己没有深究其原理,猜测可能是因为小程序对 SVGmask element 支持不太好,所以才导致这个问题,当把 mask 删掉之后,我终于“看清了它的脸”!虽然“脸”看清了,可 icon 的样式都变了,但从 Figma 上导出的 icon 就是这样,所以我只能选择手撸了!

尴尬.jpeg

撸前热身🏃‍♂️

这个小小的 icon 主要由一个圆角矩形,两个半圆和两条横杠组成(原谅我如此苍白的描述,因为我确实描绘不出它的美)🌚

SVG 中,我们经常看到一个元素 <g>,这个元素理解起来很简单:g 下的所有子元素都会继承 g 上的属性。比如我们绘制两个圆:

<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
  <g fill="cyan" stroke="yellow" stroke-width="1">
    <circle cx="1" cy="1" r="10" />
    <circle cx="12" cy="12" r="6" />
  </g>
</svg>
复制代码

效果如下:

svg-g.png

两个圆形都继承了 gfill/stroke/stroke-width 属性(灰色边框是手动给 img 元素添加的),是不是很简单😄


除了 <g>,我们还常见一个元素就是 <path>path 中有个属性叫做 ddraw 的缩写),d 中的内容看了更是头大!不要慌,让我来带你梳理一下🧶

path 元素很好理解,就是绘制我们定义的制定路径的图形(这个路径可以类比 PhotoShop 中的路径);而 d 就是绘制路径的指令,d 属性中经常看到 m/l/h/M/L/H 等各种字母并且大小写还不相同,首先你需要知道的是 每个字母都是一个指令,其后跟的就是要绘制的位置,小写的字母都是相对位置(relative),大写的字母都是绝对位置(absolute)。下面我们通过一个例子来理解:

<path
  fill="none"
  stroke="cyan"
  stroke-width="1"
  d="M 1 1
     L 10 10
     V 1
     H 6"
/>
复制代码

svg-path-a.png

<path
  fill="none"
  stroke="cyan"
  stroke-width="1"
  d="M 1 1
     l 9 9
     v -9
     h -4"
/>
复制代码

svg-path-r.png

上面我分别使用 相对指令绝对指令 绘制了两个一样的图形,绝对指令我们可以理解为 “移动到”,相对指令则可以理解为 向哪儿移动多少

那么用这种理解我们来映射到上面的两个例子中:

🌰1⃣️:画笔移动到 (1,1)(1, 1),绘制一条从 (1,1)(1, 1)(10,10)(10, 10) 的线段,绘制一条从 (10,10)(10, 10)(10,1)(10, 1) 的线段,绘制一条从 (10,1)(10, 1)(6,1)(6, 1) 的线段;

🌰2⃣️:画笔移动到 (1,1)(1, 1),绘制一条从 (1,1)(1, 1) 沿 xxyy 方向各增加 99 的线段(即 (1+9,1+9)(1 + 9, 1 + 9)),沿 yy 轴负方向移动 99 并绘制相应线段(即 (10,109)(10, 10 - 9)),沿 xx 轴负方向移动 44 并绘制相应线段(即 (104,1)(10 - 4, 1))。

怎么样,这样一看是不是很简单?下面简单介绍一下 d 的常用指令:

指令参数含义(PxP_xPyP_y 分别代表当前画笔位置)
mdx,dyd_x, d_y根据当前画笔位置沿 xx 轴移动 xx 个单位,沿 yy 轴移动 yy 个单位,(Px,Py)=(Px+dx,Py+dy)(P_x, P_y)=(P_x + d_x, P_y + d_y)
Mx,yx, y将画笔移动到 (x,y)(x, y)
ldx,dyd_x, d_y绘制一条从 (Px,Py)(P_x, P_y)(Px+dx,Py+dy)(P_x + d_x, P_y + d_y) 的线段
Lx,yx, y绘制一条从 (Px,Py)(P_x, P_y)(x,y)(x, y) 的线段
hdxd_x绘制一条从 (Px,Py)(P_x, P_y)(Px+dx,Py)(P_x + d_x, P_y) 的线段
Hxx绘制一条从 (Px,Py)(P_x, P_y)(x,Py)(x, P_y) 的线段
vdyd_y绘制一条从 (Px,Py)(P_x, P_y)(Px,Py+dy)(P_x, P_y + d_y) 的线段
Vyy绘制一条从 (Px,Py)(P_x, P_y)(Px,y)(P_x, y) 的线段

当然,d 中还有其它指令比如绘制 贝塞尔曲线 等,更多请了解:developer.mozilla.org/en-US/docs/…

不撸了,直接结束💪

说了上面的内容,再来绘制发票 icon 就迎刃而解了,就讲怎么了直接贴代码:

<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
  <g fill="#fff" stroke="#000" stroke-width="1.5">
    <rect
      x="3"
      y="5"
      rx="1"
      ry="1"
      width="20"
      height="14"
      fill="none"
    />
    <path d="M8.5 10.5h7m-7 3.5h5"/>
    <path d="M2.7 9a.5.5 0 1 1-.1 6m20.9-6a.5.5 0 1 0 0 6" />
    <path stroke="none" d="M0 9.5h3v5H0zm23 0h3v5h-3z"/>
  </g>
</svg>
复制代码

看下效果如何:

invoice.png

删去了 mask 在小程序中也能正常显示了:

清晰.png

细心的读者可能发现上面多了一个 viewBox 属性,该属性允许指定一个给定的一组图形伸展以适应特定的容器元素,也就是当我们设置 icon 大小时,svg 也会跟随我们设置的尺寸相应伸缩不会被裁减。各位可以试一下删去这个属性,然后使用 CSSicon 的尺寸缩小,该 icon 会被裁掉。

到现在,我们的 icon 就已经画好了,但还没结束~我们想使用 CSScolor 来设置 icon 的颜色,这个问题很简单,CSS 中有个 currentColor 我们把 SVGstroke 值设为 currentColor 然后在父元素设置 color 即可;而使用 font-size 来控制 icon 大小也只需要将 svgwidthheight 的值设为 1em 即可:

.container {
  color: red;
  font-size: 48px;
}
复制代码
<div class="container">
  <svg width="1em" height="1em" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
    <g fill="#fff" stroke="currentColor" stroke-width="1.5">
      <rect
        x="3"
        y="5"
        rx="1"
        ry="1"
        width="20"
        height="14"
        fill="none"
      />
      <path d="M8.5 10.5h7m-7 3.5h5"/>
      <path d="M2.7 9a.5.5 0 1 1-.1 6m20.9-6a.5.5 0 1 0 0 6" />
      <path stroke="none" d="M0 9.5h3v5H0zm23 0h3v5h-3z"/>
    </g>
  </svg>
</div>
复制代码

看下效果:

colored.png

不过如此,索然无味!

不过如此.jpeg

---- 到此结束,这次还是不闲扯,我要做一个沉稳的 Boy ----

文章分类
前端
文章标签