icon 的各种使用姿势与管理方案

发布时间 2024-01-02 18:59:52作者: manyuemeiquqi

在现代的用户界面设计中,图标(Icon)起着非常重要的作用。它们不仅可以增加界面的美观性,还可以提供直观的视觉指示和交互元素。在本文中,我们将探讨 icon 的各种使用姿势与管理方案。
与传统的位图图标相比,SVG(可缩放矢量图形)图标具有许多优势。首先,SVG 图标是矢量图形,可以无损缩放到任意大小而不失真。这使得它们在不同的设备和分辨率下保持清晰和锐利。其次,SVG 图标是基于文本的,可以通过修改其属性和样式来自定义。这为开发人员和设计师提供了更大的灵活性和可定制性,因此业务中基本使用 SVG 呈现 icon。

首先需要有一个 SVG,我手头上没有现成的,就以开源 Github SVG 为例,下载得到压缩包,就用 github-mask 这个资源进行各种使用姿势的讲述。
image.png

SVG 的使用方式

我个人将 SVG 的在浏览器(不考虑跨平台)上的使用分为两类,第一类,以 SVG 标签作为载体进行呈现,第二类,以其他标签作为载体呈现。

SVG 作为承载主体

Inline SVG

即直接把 SVG 引入 HTML 内部:
image.png

Symbol SVG

该种方式就不过多介绍,简单来说就是使用 symbol 定义图形,使用 use 进行实例化。
image.png

Web Components

该种方式也是为了解决行内 SVG 的痛点,通过 Web Components 进行 HTML 的节点注册,也就是借助 Web Component 秽土转生。
image.png

其他标签作为承载主体

字体化处理

原理就是将 SVG 转换为新注册的一个字体文件,字体文件内部进行了 icon 码点分配与注册,使用时借助字体完成 icon 的渲染。

这里我们可以通过 fontello 这个工具进行体验,将文件拖入网站后,确认 icon 的 unicode 后进行文件转换,就可以得到字体文件。image.pngimage.png

然后在 CSS 中引入字体文件进行自定义字体的注册,使用时通过 i 元素 + 字体编码就可以渲染 icon。
image.png

然而这种方式的缺点是开发者很难从编码中获取 icon 的过多信息。
但是如果将字体跟 CSS 绑定在一起呢?
也就是以 class 命名的方式语义化 icon,使用时通过伪元素的方式进行渲染(可以理解为字体编码的语义化处理)。
image.png

SVG in image
  • file path
  • Data URI

不多进行赘述,一个是资源请求路径,一个是 base64。

image.png

SVG in background

我们知道,background 除却可以设置颜色外,业务中还经常作为元素背景图进行渲染,同样对于 SVG,也可以进行类似处理。
image.png
诚然,我们可以通过 height width 来控制 icon 的大小,但是这样方式对 SVG 的线条颜色是无能为力的。
但有一方案(css-mask)可以曲线救国,原理类似于 PS 软件的蒙版思想,将 icon 进行裁剪设置为元素蒙版,然后对蒙版进行颜色控制。
image.png

但是这种方案也有缺陷,蒙版会影响到彩色图标的渲染,具体看[聊聊纯 CSS 图标](聊聊纯 CSS 图标),简单来说,彩色图标无法通过 currentColor 进行 icon 还原。
UnoCSS 预设的 icon 的解决方案是将两种方案进行了结合,通过一个条件进行渲染方式的调整,通过这种方式就可以将 icon CSS化,给元素赋值 class 就可进 icon 的渲染。

消费方案

聊完 SVG 的各种存在形态,我们在说说 SVG 在前端框架下的消费方式,上述的各种使用方案在下面的消费方案中都有体现。

一处引入,多处消费(雪碧图的思想)

  • iconfont

阿里的 iconfont 提供了一个 icon 的管理平台,通过该平台,可以将项目所需 icon 统一管理,然后生成一份文件,然后将所需 SVG 集中引入。

image.png
平台提供两种文件的输出,一种是 SVG 字体化的文件,另外一种是一个 JS 文件,以供我们进行 SVG Symbol 形式的引入,原理也很简单,就是为 icon 分配好各种 id 后,集中到一个 SVG 标签内部,插入到 body 内。
image.png
image.png

平台虽然提供在线 CDN 链接,但是不建议使用,因为会这样
image.png

有条件的同学上传到公司服务器,没有条件的跟打包文件放在一起即可。

  • iconpark

iconpark 是字节系的 icon 管理平台
image.png
同理,上传 SVG 后,对外提供 SVG 的两种打包处理后的文件,一种是 SVG Symbol 标签创建文件,就不进行重复了,另外一种是 Web Component 的注册文件,原理就是 define element,同时 iconpark 进行了其他属性的封装,以供对 icon 样式进行调整。
image.png

业务实践中,上述消费方式足以满足大部分业务形态,但有两点需要考究

  • 目前大部分前后端业务开发都升级到 HTTP2 通信方式,多路复用已经对大量 HTTP 请求的场景进行优化处理,是否还需要进行雪碧图的制作
  • 对于需要大量使用 icon 的场景,例如聊天表情框,icon 数量与引入的打包文件体积成正比,部分用户可能不需要打开聊天框但仍要承担加载大量 icon 所带来的加载速度减慢的后果。

按需引入

  • 交给打包工具

以 vite 为例,vite-svg-loaderunplugin-icons 都提供了在 DSL 中引入 SVG 的功能(只针对 component 引入),原理也很简单,就是将 SVG 转换为字符串(Inline SVG 字符串)后,转化为虚拟 DOM 的数据结构,交付给渲染框架进行转换,得到的产物就是封装后的组件。

iconify 是一个开源 icon 设计库,提供了大量 icon 以及 icon 的使用方法。对 SVG 的主要使用方式有两种,第一种是 Web Component,另外一种就是 SVG in background(Uno CSS)。原理就是 iconify 将该平台的 SVG 转化成一种类似的 JSON 数据格式,根据该 JSON, iconify 提供了各种各样的 icon 的 web component 与 CSS 的线上打包文件,以此达到按需加载。
image.png
iconify 的定位主要面向开源开发者,因而单纯使用 iconify 在生产中的价值不是很大,生产中除了组件库跟设计师的 icon,开源 icon 几乎不会使用,但如果想在 iconify 的基础上进行自定义图标处理,无论是 SVG in HTML 还是 SVG in CSS,都还需要搭配一些工具进行数据转换处理,成本较高,因此不推荐。

  • 发包处理

上述方案都或多或少受到平台跟工具的限制,如果想完全可控化,直接借鉴组件库对 icon 的处理思路,团队发包维护,这样 SVG 的展现形式都可以业务形态进行调整。
如果想对外引用方式为渲染组件,可以借鉴 ant-design-icon ,具体思路为使用 parseXML(opens in a new tab) 进行节点解析后,定义好模板后,往里模板里塞数据然后暴露即可。
该方案好处是极度可控,但不适合频繁调整 icon 的团队。

不只是 svg

之前,Web 中想要使用矢量的彩色图标只能通过 SVG 的方式,但除了 SVG,我们还有其他更好的选择

总结

消费端可进行各自业务调整,这里进行使用方式的总结。
SVG Symbl 使用方式

  • 支持多色图标了,不再受单色限制。
  • 兼容性较差,支持 ie9+,及现代浏览器。
  • 浏览器渲染 SVG 的性能一般,还不如png。

font 使用方式

  • 兼容性良好,支持ie8+,及所有现代浏览器。
  • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。

web component 使用方式

  • 体验最好
  • 兼容性较差,不支持 id
  • 内部本质仍是 SVG Symbol

SVG in background 使用方式

  • 兼容性较差,不支持 id
  • 不受单色限制
  • 样式调整更加方便

本文的各种使用姿势都可在 repo 获得

本文所涉及的技术在 vue-tsx-admin 中可以找到完整的实例,希望对你写 Vue 的项目有所帮助。欢迎 star 和提出不足。
系列文章: