前端自定义字体、iconfont,你学废了吗?
文章目录
一、自定义字体简介
@font-face是CSS3中的一个模块,他主要是把自己定义的Web字体嵌入到你的网页中,@font-face这个功能早在IE4就已经支持。指定的字体可以从远程服务器或者用户本地安装的字体加载,语法规则:
@font-face {
font-family: <YourWebFontName>;
src: <source> [<format>][,<source> [<format>]]*;
[font-weight: <weight>];
[font-style: <style>];
}
参数说明:
1、YourWebFontName:自定义的字体名称,最好是使用你下载的默认字体。
2、source:自定义的字体的存放路径,可以是相对路径也可以是绝路径;
3、format:自定义的字体的格式,主要用来帮助浏览器识别,其值主要有以下几种类型:truetype,opentype,truetype-aat,embedded-opentype,avg等;
4、weight和style:weight定义字体是否为粗体,style主要定义字体样式,如斜体。
浏览器兼容:
二、字体格式
TureTpe(.ttf)格式: Windows和Mac的最常见的字体,是一种RAW格式,因此他不为网站优化,可以任意缩放和旋转不会出现锯齿,支持这种字体的浏览器有:IE9+,Firefox3.5+,Chrome4+,Safari3+,Opera10+,iOS Mobile Safari4.2+
OpenType(.otf)格式:.otf字体被认为是一种原始的字体格式,是可缩放性的电脑字体类型,是微软与Adobe共同开发用来替代TrueType的新字形,其内置在TureType的基础上,所以也提供了更多的功能,支持这种字体的浏览器有:
Firefox3.5+,Chrome4.0+,Safari3.1+,Opera10.0+,iOS Mobile Safari4.2+
Web Open Font Format(.woff)格式:.woff字体是Web字体中最佳格式,专门为了We设计的字体格式标准,他是一个开放的TrueType/OpenType的压缩版本,并针对网络使用进行了优化,同时也支持元数据包的分离,支持这种字体的浏览器有:
IE9+,Firefox3.5+,Chrome6+,Safari3.6+,Opera11.1+
Embedded Open Type(.eot)格式: 微软开发的IE专用嵌入字体格式,可以从TrueType创建此格式字体,支持这种字体的浏览器有:IE4+
SVG(.svg)格式:.svg字体是基于SVG字体渲染的一种格式,其中.svgz是使用了Gzip压缩的SVG字体,但 IE 或 Firefox 从不支持它,并且现在 Chrome 也放弃了对它的支持。因此,它的用途很有限,本指南中有意将其忽略。支持这种字体的浏览器有:
Chrome4+,Safari3.1+,Opera10.0+,iOS Mobile Safari3.2+
我们可以根据项目需求来判定使用哪种字体,一般其实.ttf格式就可以满足需求,但如果项目想要兼容多种低版本浏览器,这就意味着在@font-face中我们至少需要.woff,.eot两种格式字体,甚至还需要.svg等字体达到更多种浏览版本的支持。Paul Irish写了一个独特的@font-face语法叫Bulletproof @font-face,让各多的浏览器支持,可以写成:
@font-face {
font-family: 'YourWebFontName';
src: url('YourWebFontName.eot'); /* IE9 Compat Modes */
src: url('YourWebFontName.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('YourWebFontName.woff') format('woff'), /* Modern Browsers */
url('YourWebFontName.ttf') format('truetype'), /* Safari, Android, iOS */
url('YourWebFontName.svg#YourWebFontName') format('svg'); /* Legacy iOS */
}
三、字体下载地址
查阅网上资料,可以在Webfonts,Typekit,Kernest,Google Web Fonts,Kernest,Dafont,Niec Web Type,寻找自己需要的字体,可根据需求自行瞎子啊,但个人推荐使用字客网。
注意:字体下载时,如果是应用于商业项目一定要注意一下版权问题,避免不必要的商业纠纷。
字体下载往往会只有其中一种格式字体,当我们需要.eot,.woff,.ttf,.svg字体格式。我给大家推荐一款好用的工具fontsquirrel,点这里进入到下面这个界面吧。
四、使用实例
以项目中Let’s go Digital Regular 字体为例,使用场景为vue-cli4,style-resources-loader预加载
function addStyleResource(rule) {
rule.use('style-resource')
.loader('style-resources-loader')
.options({
patterns: [
path.resolve(__dirname, './src/styles/fonts.less'),
]
});
}
使用这种形式,因为业务场景,.ttf格式便可以满足需求,在引入文件地址时会有路径问题,因为style-resources-loader使用绝对路径导致,所以这里我们采用这种方式来引入:
@font-face {
font-family: 'LetsgoDigital-Regular';
src: url('~@/assets/fonts/digital-regular.ttf') format('truetype');
}
最终页面上效果:
五、前端实现字体压缩
当项目中需要引入很多自定义字体时,会发现字体库体积很大,比如常用的PingFangSC-Regular字体库就有14M,因此压缩是必不可少的。
推荐使用font-spider,也可以使用Fontmin,相对于font-spider而言比较方便的是有一个客户端操作界面。
font-spider的工作原理是这样的: 中文字体文件之所以很大,是因为英语只有26个字母,而中文的汉字有好多好多个,所以文件相对来说就会大很多。font-spider就是从你的css文件的@font-face入手,去查找字体,然后遍历你的html文件,通过分析本地 CSS 与 HTML 文件获取 WebFont 中没有使用的字符,并将这些字符数据从字体中删除以实现压缩,同时生成跨浏览器使用的格式。
注意:这种是把fonts.html中没有引用的字体删除,从而达到压缩的效果!!!!!如果是整个中文包压缩,这种方式就很不适用了!!!
在vue中使用时,可创建一个fonts.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
@font-face {
font-family: 'lcdd';
src: url('./src/assets/fonts/pingfangsc-regular.ttf');
src: url('./src/assets/fonts/pingfangsc-regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
.test {
font-family: 'lcdd';
}
</style>
</head>
<body>
<h2 class="test">12345678.980%</h2>
</body>
1.安装font-spider :npm install font-spider -g
2.进入fonts.html所属文件夹下,执行font-swiper fonts.html
3.生成.font-spider存储之前未压缩字体,压缩后字体仅有4k
压缩后:
压缩前:
六、字体加载
虽然有压缩的功能,但必须提供出所有使用过的字体,而且我想的是我的项目中就默认一个好看的字体。
这样就遇到一个问题,在第一次加载的时候,浏览器就会用一些时间来加载这个字体文件。
而在加载完成之前,页面就会空白,也就是FOIT(Flash of Invisible Text)
- FOUT(不推荐)
FOUT(Flash of Unstyled Text)大意就是在字体加载完成前,浏览器会显示font-family
的顺序字体
当加载完成后,才会替换成定义的字体,设置如下:
@font-face {
...
font-display: swap;
...
}
这样设置之后依旧会有字体闪动的效果,只是初始由白屏变为了默认字体,体验依旧不好,不推荐。
-
FontFaceObserver
判断字体加载完添加loading动画,使用fontfaceobserver,安装:npm i fontfaceobserver
b.
// css 中 @font-face 已定义好 import FontFaceObserver from 'fontfaceobserver' loadfont(){ console.time("字体加载用时") var ooo = new FontFaceObserver('Regular') ooo.load().then(() =>{ document.getElementById('index').style.fontFamily = 'Regular' console.timeEnd("字体加载用时") }) },
同时可以结合通过 HTTP 缓存优化字体重复使用
字体资源通常是不会频繁更新的静态资源。因此,它们非常适合较长的 max-age 到期 - 确保您为所有字体资源同时指定了条件 ETag 标头和最佳 Cache-Control 策略。
无需在 localStorage 中或通过其他机制存储字体,其中的每一种机制都有各自的性能缺陷。 浏览器的 HTTP 缓存与 Font Loading API 或 webfontloader 内容库相结合,实现了最佳并且最可靠的机制来向浏览器提供字体资源。
七、web端使用iconfont自定义图标
阿里iconfont相信大家都是用过,这里不对注册等流程做过多赘述,直接说一下使用方式。
使用途径一:icon单个使用(不推荐)
单个图标用户可以自行选择下载不同的格式使用,包括png,ai,svg。此种方式适合用在图标引用特别少,以后也不需要特别维护的场景。比如设计师用来做demo原型、前端临时做个活动页、下载图标做PPT等。在项目中不推荐使用此种方式
使用途径二:unicode引用(不推荐,主要原因:不支持多色图标,书写不直观,语意不明确)
unicode是字体在网页端最原始的应用方式,特点是:
- 兼容性最好,支持ie6+,及所有现代浏览器。
- 支持按字体的方式去动态调整图标大小,颜色等等。
- 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
- 在不同的设备浏览器字体的渲染会略有差别,在不同的浏览器或系统中对文字的渲染不同,其显示的位置和大小可能会受到font-size、line-height、word-spacing等CSS属性的影响,而且这种影响调整起来较为困难
注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式
第一步:拷贝项目下面生成的font-face
@font-face {font-family: 'iconfont';
src: url('iconfont.eot');
src: url('iconfont.eot?#iefix') format('embedded-opentype'),
url('iconfont.woff') format('woff'),
url('iconfont.ttf') format('truetype'),
url('iconfont.svg#iconfont') format('svg');
}
第二步:定义使用iconfont的样式
.iconfont{
font-family:"iconfont" !important;
font-size:16px;font-style:normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
}
第三步:挑选相应图标并获取字体编码,应用于页面
<i class="iconfont">3</i>
使用途径三:font-class引用(无多色图标,可根据需要判断使用场景)
font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。
但一定要注意命名空间的问题,否则一上线引发了各种雪崩问题。与unicode使用方式相比,具有如下特点:
- 兼容性良好,支持ie8+,及所有现代浏览器。
- 相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。
- 因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。
- 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
使用步骤如下:
第一步:拷贝项目下面生成的fontclass代码:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.css
第二步:挑选相应图标并获取类名,应用于页面:
<i class="iconfont icon-xxx"></i>
使用途径四:symbol引用(多色图标推荐使用,也是目前使用人数比较多的方式)
svg
的symbol
提供了类似于雪碧图的功能,让svg
的使用变得更简单,也可以满足做图标系统的需求,这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 这种用法其实是做了一个svg的集合,与上面两种相比具有如下特点:
- 支持多色图标了,不再受单色限制。
- 通过一些技巧,支持像字体那样,通过
font-size
,color
来调整样式。 - 兼容性较差,支持 ie9+,及现代浏览器。
- 浏览器渲染svg的性能一般,还不如png。
使用步骤如下:
第一步:拷贝项目下面生成的symbol代码:
//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js
第二步:加入通用css代码(引入一次就行):
<style type="text/css">
.icon {
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
第三步:挑选相应图标并获取类名,应用于页面:
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-xxx"></use>
</svg>
八、简单使用iconfont
a. 创建 icon-component 组件
<template>
<svg class="svg-icon" aria-hidden="true">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script lang="ts">
import {Component, Vue, Prop} from 'vue-property-decorator';
@Component
export default class IconSvg extends Vue {
@Prop({required: true}) iconClass!: string;
get iconName() {
return `#icon-${this.iconClass}`;
}
}
</script>
<style scoped lang="less">
.svg-icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
</style>
b. 引用组件,可根据需求判定是否注册为全局组件
<icon-svg icon-class="icon-name"/>
九、 更加优雅的导入svg
上面的方式使用的iconfont官方推荐的方式引用的。这种方式有很多缺陷,比如
-
他是通过js来生成svg的代码,icon映射关系不明了,是以下面形式展示
-
做不到按需加载,不能根据我们使用了那些 svg 动态的生成
svg-sprite
-
自定义性差,通常导出的svg包含大量的无用信息,例如编辑器源信息、注释等。通常包含其它一些不会影响渲染结果或可以移除的内容。
-
重点!!!!添加方式很不友好,icon更新需要每次重新生成iconfont.js,很麻烦
svg-sprite-loader按需加载
所以,我们可以借助 svg-sprite-loader 来实现按需加载。 svg-sprite-loader 它是一个 webpack loader ,可以将多个 svg 打包成 svg-sprite
。根据导入的 svg 文件自动生成 symbol 标签并插入 html。
svg-sprite-loader优点:
- 页面代码清爽
- 可使用 ID 随处重复调用
- 每个 SVG 图标都可以更改大小颜色
但是我们发现vue-cli
默认情况下会使用 url-loader
对svg进行处理,会将它放在/img
目录下,所以这时候我们引入svg-sprite-loader
会引发一些冲突。参考文章vue-cli3中webpack 相关配置,其中配置了include和exclude,请参考文章vue-cli3中webpack 相关配置。本来只添加svg-sprite-loader就行了,但是svg也是图片的一种,所以file-loader也会对其进行处理,所以就会冲突,解决的办法就是,在项目中新建一个文件icons,使用file-loader编译svg的时候不编译icons里面的图标。
// vue.config.js
const path = require('path')
module.exports = {
chainWebpack: config => {
const svgRule = config.module.rule('svg')
// 清除已有的所有 loader。
// 如果你不这样做,接下来的 loader 会附加在该规则现有的 loader 之后。
svgRule.uses.clear()
svgRule
.test(/\.svg$/)
.include.add(path.resolve(__dirname, './src/icons'))
.end()
.use('svg-sprite-loader')
.loader('svg-sprite-loader')
.options({
symbolId: 'icon-[name]'
})
const fileRule = config.module.rule('file')
fileRule.uses.clear()
fileRule
.test(/\.svg$/)
.exclude.add(path.resolve(__dirname, './src/icons'))
.end()
.use('file-loader')
.loader('file-loader')
}
}
配置完成之后,可以检查一下配置是否生效:
-
vue inspect:控制台会显示你的webpack所有的配置
-
vue inspect --rules 显示所有的rule配置规则
-
vue inspect --rule svg (我们在上面配置了svg)
<icon-svg icon-class="icon-geren-copy" /> // 使用方式
import '@/icons/icon-Shapecopy.svg'; // 引入方式
自动导入所有图标
通过上面的方式,每次引入图标都需要
import '@/icons/icon-Shapecopy.svg';
import引入我们需要的图标,很麻烦,这里我们可以使用自动导入所有图标。之后我们就要使用到 webpack 的 require.context。简单的说就是可以正则匹配引入相应的文件模块。例如:
require.context("./test", false, /.test.js$/);
这行代码就会去 test 文件夹(不包含子目录)下面的找所有文件名以 .test.js 结尾的文件能被 require 的文件。
require.context有三个参数:
- directory:说明需要检索的目录
- useSubdirectories:是否检索子目录
- regExp: 匹配文件的正则表达式
直接上配置代码:
import Vue from 'vue';
import IconSvg from '@/components/icon/icon-svg.vue';
Vue.component('icon-svg', IconSvg);
const requireAll = (requireContext) => requireContext.keys().map(requireContext);
const req = require.context('../../icons', false, /\.svg$/)
requireAll(req);
通过这种方式我们使用图标时就不需要import啦~ 是不是很方便?
这里附上SVG在线压缩合并工具与SVG Sprites还原与管理在线工具。另外附上好用的工具svgo 官方文档 张鑫旭大大的文章。
svg延伸
写到这里我产生了一个疑问,为什么一定要用svg?png与iconfont字体他不香吗?这里做一下简单的介绍,更多延伸可以参考:这篇文章
先说一下与icon font对比:
- 渲染方式不同,icon font采用的是字体渲染,icon font在一倍屏幕下渲染效果并不好,在细节部分锯齿还是很明显的,SVG上面我说过它是图形所以在浏览器中使用的是图形渲染,所以SVG却没有这种问题,请看下图对比:
- icon font只能支持单色,因此这也成为了icon font的一个瓶颈。
- icon font主要在页面用Unicode符号调用对应的图标,这种方式不管是浏览器,搜索引擎和对无障碍方面的能力都没有SVG好
所以,根据我的理解简单的说,svg更适合做图标,因为它更加高清且支持多色。
十、字体加密,反爬虫
大众点评评论数据抓取 反爬虫措施有css文字映射和字体库反爬虫。
大众点评的反爬虫手段有那些?比如:封ip,封账号,字体库反爬虫,css文字映射,图形滑动验证码。
目前很多主流网站其实用到的很少,极为典型的就是大众点评,这里只做一下简单的介绍。具体的一些内容可参考文献:css反爬虫。目前反爬虫大概为两类,第一种是svg引用的方式,第二种是字体库反爬虫。
字体加密原理
字体加密其实是将一种特定的字体库来代替浏览器本身的字体库显示的过程。用凯撒加密的方式将明文(下图的原文)替换为密文(下图的阴书),加密的密钥(也就是下图字验)就是上面font-face
声明的自定义字体,加密好之后,HTML源码中是密文,使用自定义字体作为密钥进行CSS解密,渲染在页面上的就是解密后的正常的明文了。
svg加密
这一种对应文本为空,只能通过 class 属性区分,点击检查,可以看到右边属性中有一个 background-image url ,这个以 svg 为后缀的文件是一种可伸缩矢量图形,通过他来对应字体。然后在svg中找到对应的文字。但这种方式现在已经被摒弃掉了,目前已经没有网站在使用了。
字体库加密
字体库反爬虫是大众点评目前在使用的手段,主要在页面上展示的效果如下:
我们可以从对应资源中查找字体资源
然后通过工具FontCreator 打开该字体文件。
由于大众点评对相应的 unicode 码进行了处理,所以就只能使用一些识图的 api 或者工具,识别出其中的内容,并保存构造相应的字典。因为大众点评的字体文件会更新,所以建议可以保存到 reids 中,方便处理。
因为这种方式少数注重数据的网站会采用,这里就不详细赘述了。如果以数据为核心资产的项目,可以尝试使用这种加密方式。
参考文献:https://www.w3cplus.com/content/css3-font-face
https://developer.mozilla.org/zh-CN/docs/Web/CSS/@font-face
https://segmentfault.com/a/1190000019262268
https://juejin.im/post/59bb864b5188257e7a427c09