最近做小程序开发,本来是个私人的小项目,所以一开始都是从 iconfont 上下载png文件再用图片标签引入的,后来想实现图标的点击态变色,发现以前的方案太原始太落后,不好维护,还是得上矢量图形的引入方案。然后就开始尝试照搬Web中引入iconfont图标的解决方案,才发现事情并没有想象的这么简单。
小程序的环境和Web挺有几分相似,但又不是完全一样,所以iconfont推荐的三种方案并不都是可行的,尝试的过程中一路走了不少坑,此文记录探索过程中的思考与感悟。
如果对 iconfont的三种图标引入方案不甚了解,可以移步前文查看:Web 页面中引用 iconfont 图标。
iconfont 提供的三种方案中,Unicode和Font Class都是引入CSS样式通过自定义字体来实现的,Symbol是引入自定义脚本来实现的,我们先来测试一下Font Class方案的可行性。
Font Class 方案探索
先考虑这样一个问题,能不能直接引入外部的CSS样式文件呢?
答案是不能,官方给出的信息 如下:
使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径,用;表示语句结束。
也就是说,只能从本地导入WXSS格式的样式文件。
我们知道,小程序中的WXSS基本上就是Web中的CSS,支持大多数的CSS选择器和样式,那么我们就试试将Font Class的CSS代码直接拷贝到小程序的WXSS文件中看一下。
将Font Class的样式引用链接复制到浏览器中直接打开:
在小程序目录下新建WXSS文件,将CSS代码复制进来:
1 | @font-face {font-family: "iconfont"; |
在根目录下的 app.wxss
文件中导入该文件:
1 | @import 'libs/style/iconfont.wxss'; |
在测试页面上插入引用标签:
1 | <i class="iconfont icon-playing"></i> |
在微信开发者工具中查看效果如下:
得到结论:Font Class方案可行,具体实现步骤如上。
此前在网上看到比较主流的说法是:小程序的WXSS文件中 font-face
的url不接受http地址作为参数,并给出了通过 transfonter 将字体转为base64格式编码再引入的方案。
出于好奇,我就研究了一下这种说法。
当前iconfont的Font Class引用链接中是直接包含了字体的base64格式编码的,不需要再通过 transfonter 网站自行转换了,以上说法应该是基于旧版本的iconfont提出的。关于WXSS的 font-face
是否支持http地址作为字体源,我把 iconfont的 Unicode 引用代码复制到了小程序中:
1 | @font-face { |
经过测试,发现在WXSS中通过url地址直接引入外部字体的方法是可行的,只是存放字体的服务器需要允许跨域。
Symbol 方案探索
那么iconfont推荐的Symbol方案是否可行呢?
该方案需要在页面中引入JS脚本,所以需要先考虑这样一个问题:能否在小程序中直接引入外部JS脚本?
答案是不能,小程序只支持通过 require 的方式引入本地的JS脚本。就算把Symbol的脚本下载到本地引入也没有意义,因为小程序中压根就不存在window顶级对象,也没有HTML中那一套DOM操作接口,更别提通过JS脚本插入节点元素了。所以这条路是彻底走不通的。
真机环境下原生组件不显示图标
我曾以为只是这样简单就可以完美解决小程序引入iconfont图标的问题了,我开开心心的在 live-player
组件中引用入 cover-view
组件和iconfont 图标来控制播放器行为:
1 | <live-player |
微信开发者工具中显示如下:
当我在手机上预览的时候就傻了,图标居然不显示了:
测试了一下真机环境下的普通视图容器中是可以显示icon的,所以首先排除字体引入失败的可能性。
查看官方文档的时候注意到了官方的 友情提示:
在工具上,原生组件是用web组件模拟的,因此很多情况并不能很好的还原真机的表现,建议开发者在使用到原生组件时尽量在真机上进行调试。
看来是 live-player 原生组件的问题。
官方对于这一块内容的 相关描述 如下:
原生组件是脱离在 WebView 渲染流程外的,层级是最高的,无视其他元素的 z-index 属性。小程序为了解决原生组件层级最高的限制,专门提供了 cover-view 和 cover-image 组件,可以覆盖在部分原生组件上面。
于是我尝试将标签 <i />
改为 <cover-view />
或 <button />
,依然没解决问题,真机下还是不显示图标。
然后我开始在社区寻找解决方案,发现还是有不少人遇到了相同的问题的。
其中有人提到是否是 cover-view 不支持伪元素,验证了一下真机环境下确实不显示 :before
伪元素中的 content
内容,看来开发者工具中对伪元素的支持确实是web组件模拟原生组件留下的副产物。
Unicode 方案探索
为了绕开这个坑,我又尝试使用iconfont的 Unicode方案,直接在 cover-view 标签内书写 html 转义字符:
1 | <cover-view class="icon"></cover-view> |
结果转义字符直接被原封不动的显示出来了,并没有转成图标字体。
经查,小程序中不支持直接使用转义字符,只有 text 标签可以通过设置 decode 属性后来支持转义字符,并且可以解析的转义字符也及其有限:
decode可以解析的有
<
>
&
'
 
 
1 | <!-- 转义成功 --> |
因此,由于小程序不支持转义字符,所以Unicode的方案也宣告失败。
最后,在一篇社区讨论贴 cover-view中使用iconfont图标无法显示 中看到了一个官方的回答:
看来原生组件中的图标引入方案除了 cover-image 标签也别无他法了。
结束语
本文探索了iconfont三种引用方案在小程序中的实现可行性:
- 小程序不支持转义字符,所以Unicode方案宣告失败。
- 小程序中可以通过
font-face
引入外部字体,所以Font Class方案可行。 - 小程序不支持引入外部JS脚本,且没有DOM接口,所以Symbol方案宣告失败。
虽然 Font Class 方案可以在小程序中引入iconfont图标,但是无法应用到原生组件中,原生组件中的图标只能以图像的形式引入。