CSS – Icon


前言

Icon 并不容易搞. 市场有许多平台支持 Icon, 有些收费有些免费. 有些 icon 很丰富, 有些很缺失. 

尤其是在做网站的时候寻找 icon 是一个挺累的事情. 这篇就来聊聊 icon.

各大平台

1. Material Icons

Google 出的, 免费, 缺点是少, 它有 Font, SVG, PNG.

2. fontawesome

这个算是鼻祖吧. v4 是完全免费的, v5 后开始部分收费了. 

支持 Font, SVG, PNG.

3. SVG Repo

这个不错, 可以找到蛮多 icon 而且免费. 但只有 SVG.

4. ICONS8

它是 LUNACY 公司的 product, 和 SVG Repo 一样 icon 挺多的, SVG 单个下载时免费的, collection 功能就收费.

5. Flaticon

以前没有收费时, 它是最好的 (Font, SVG, PNG),但现在收费了. 没有付费只能下载 PNG...

6. ionicons

Ionic Framework 的其中一个 product. 免费的, 但它和 Material Icons 一样的少. 用它倒不如用 Material Icons.

有 Font 和 SVG

Font vs SVG

有 2 种方式可以使用 icon, 一种是 Font, 一种是 SVG. 来对比一下呗.

参考: Material Design Icons: Font vs SVG. And how to use SVG Sprites in Angular?

1. implement

Font 比 SVG 容易 implment 许多 (除非你只需要一个 SVG icon 就还好, 超过一个 SVG 就不容易了)

2. change color

Font 直接换就可以了, SVG 需要用 online tool BOXY SVG, 或者修改 svg fill, 比较麻烦.

3. bundle size

Font 一定要那么大, SVG 是按需, 所以 SVG 通常小许多. 但需要搞一套 Gulp sprite sheet 维护 (增加了架构的复杂度)

4. 歪掉

Font 在小尺寸可能会歪掉, SVG 没有这种问题, 整个是 material icon 的例子:

建议: 如果是做 Web App, 通常就使用 font way, 方便. 如果只是想用小部分的 icon, 那么可以用 SVG, 不比引入 CSS / JS.

Font 和 SVG 的引入形式

Font 形式是, 加载 CSS Link / JS Script 库. 通过 font-family, size, color 来调用 icon.

element 通常使用 或者 span.

SVG 形式是, 下载 SVG > 优化 SVG > 合并多个 SVG to 1 个 SVG sprite sheet file.

用 ajax 加载 SVG sprite and append to HTML, 通过 svg element + #id 选用.

SVG 工程比较大, 虽然可以借助自动化工具, 但是 setup 也是挺复杂的.

开发 Web App 的话建议使用库就好, 如果要用 SVG, 性能不在意的话就直接 1 个 1 个 img 请求 .svg 就好了.

非要搞 sprite 的话, 就用一些 gulp/webpack/online tools 做打包.

Material Icons - Google Fonts

它是免费的, Font, SVG 都有, 缺点就是太少了. 用来做 App 还行, 做网站的话, 很多 icon 找不到.

官网: fonts.google.com/icons

它有 5 大种类, default 是 Filled 也叫 baseline.

使用方式: Material Icons Guide (其它平台的使用方式也差不多的)

Font Way

导入 CSS link (有些平台是用 JS)

<link
  href="https://fonts.googleapis.com/icon?family=Material+Icons"
  rel="stylesheet"
/>
<link
  href="https://fonts.googleapis.com/css2?family=Material+Icons+Outlined"
  rel="stylesheet"
/>

用 span 或 i 写上 icon name 就可以了. 如果要调整颜色和尺寸, 直接调 CSS font 的属性即可.

<span class="material-icons" style="color: red; font-size: 40px">facespan>
<i class="material-icons-outlined">facei>

效果

Font Way Self Hosting

上面是直接连去 Google CDN, 如果想自己 host 也是可以.

去这里下载.

@font-face

@font-face {
  font-family: "Material Icons";
  font-style: normal;
  font-weight: 400;
  src: url(MaterialIcons-Regular.ttf);
}

@font-face {
  font-family: "Material Icons Outlined";
  font-style: normal;
  font-weight: 400;
  src: url(MaterialIconsOutlined-Regular.otf);
}

CSS class

.material-icons {
  font-family: "Material Icons";
  font-weight: normal;
  font-style: normal;
  font-size: 24px; /* Preferred icon size */
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;

  /* Support for all WebKit browsers. */
  -webkit-font-smoothing: antialiased;
  /* Support for Safari and Chrome. */
  text-rendering: optimizeLegibility;

  /* Support for Firefox. */
  -moz-osx-font-smoothing: grayscale;

  /* Support for IE. */
  font-feature-settings: "liga";
}

.material-icons-outlined {
  font-family: "Material Icons Outlined";
  font-weight: normal;
  font-style: normal;
  font-size: 24px; /* Preferred icon size */
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;

  /* Support for all WebKit browsers. */
  -webkit-font-smoothing: antialiased;
  /* Support for Safari and Chrome. */
  text-rendering: optimizeLegibility;

  /* Support for Firefox. */
  -moz-osx-font-smoothing: grayscale;

  /* Support for IE. */
  font-feature-settings: "liga";
}

由于它只是 CSS, 如果用 webpack 的话也可以使用  等工具, 参考: google fonts + webpack

SVG Way

如果不想引用整个 CSS link 库, 也可以使用 SVG 手法.

去官网就可以下载了, 当使用多张 SVG 时, Google 建议使用 sprite sheets 把它们合并.

我先讲一下 SVG 会遇到的问题. 由于它是图片, 只可以调整尺寸, 不能直接调颜色. 而官网下载的 SVG 只能是黑色和白色. 

调颜色有 2 种方法

1. 修改 fill 属性值, 参考: How to change the color of an svg element?

2. 使用 online tool BOXY SVG, 免费的注册账号就可以用了.

通过 img 导入即可

<img src="./home_black_24dp.svg" />

 

SVG Sprite Sheet

参考: How to create and use an SVG Sprite

一个 SVG file 长这样

 一个 SVG Sprite Sheet file 长这样

通过 symbol 把多个 SVG file 放在一个 SVG file 里面, 然后用 id 作为识别.

调用时用 svg 标签配上 URL + hash 描点 id 就可以了.

<svg style="width: 48px; height: 48px">
  <use xlink:href="sprite.svg#hot-svgrepo-com" />
svg>
<svg style="width: 48px; height: 48px">
  <use xlink:href="sprite.svg#air-conditioner-svgrepo-com" />
svg>

或者在页面某个地方(上下都可以) 放入 sprite sheet svg element

然后调用时直接放 hash 即可. 不需要 URL. (建议使用 ajax 去加载 sprite.svg 据说可缓存, 然后 inner html 参考: How to create and use an SVG Sprite)

<svg style="color: blue">
  <use xlink:href="#google">use>
svg>

调颜色

调用

<svg style="color: blue">
  <use xlink:href="sprite.svg#google">use>
svg>

 

SVG 工程化 / 工具

参考: How to create and use an SVG Sprite

流程大概是这样:

下载多个 SVG file. 

对每个 SVG file 做优化 (去除 comment 等等)

把所有 SVG combine to 1 个 SVG sprite sheet.

各种工具介绍

svgsprit.es online tool for spirte sheet

svgo Node.js SVG 优化

svg-sprite Node.js SVG sprite + 优化(基于 svgo)

gulp-svg-sprite Gulp 封装 svg-sprite

svgo-loader Webpack loader for SVG 优化 (基于 svgo)

svg-sprite-loader Webpack loader for sprite (没有优化哦, 要优化就和 svgo-loader 一起用)

svg-sprite-generator 视频介绍的, 适合不懂 coding 的 designer 使用, 它好像是 folk SmartIcons 的.

svgo 使用

参考:

svgo

使用Svgo优化svg代码-爱代码爱编程

全局安装

npm -g install svgo

优化 files

svgo one.svg two.svg -o one.min.svg two.min.svg

优化 folder

svgo -f ./path/to/folder/with/svg/files -o ./path/to/folder/with/svg/output

config 用默认的就可以了, 或者用视频里的 svgo-config.json

默认 config 名字 svgo.config.js

{
  plugins: [
    {
      cleanupAttrs: true,
    },
    {
      removeDoctype: true,
    },
    {
      removeXMLProcInst: true,
    },
    {
      removeComments: true,
    },
    {
      removeMetadata: true,
    },
    {
      removeTitle: true,
    },
    {
      removeDesc: true,
    },
    {
      removeUselessDefs: true,
    },
    {
      removeEditorsNSData: true,
    },
    {
      removeEmptyAttrs: true,
    },
    {
      removeHiddenElems: true,
    },
    {
      removeEmptyText: true,
    },
    {
      removeEmptyContainers: true,
    },
    {
      removeViewBox: false,
    },
    {
      cleanUpEnableBackground: true,
    },
    {
      convertStyleToAttrs: true,
    },
    {
      convertColors: true,
    },
    {
      convertPathData: true,
    },
    {
      convertTransform: true,
    },
    {
      removeUnknownsAndDefaults: true,
    },
    {
      removeNonInheritableGroupAttrs: true,
    },
    {
      removeUselessStrokeAndFill: true,
    },
    {
      removeUnusedNS: true,
    },
    {
      cleanupIDs: true,
    },
    {
      cleanupNumericValues: true,
    },
    {
      moveElemsAttrsToGroup: true,
    },
    {
      moveGroupAttrsToElems: true,
    },
    {
      collapseGroups: true,
    },
    {
      removeRasterImages: false,
    },
    {
      mergePaths: true,
    },
    {
      convertShapeToPath: true,
    },
    {
      sortAttrs: true,
    },
    {
      transformsWithOnePath: false,
    },
    {
      removeDimensions: true,
    },
    {
      removeAttrs: { attrs: "(stroke|fill)" },
    },
  ];
}

指定 config path

svgo one.svg -o one.min.svg --config ./path/myconfig.js

 

svg-sprite-loader 使用

svg-sprite-loader 这个工具可以做到通过 js import svg, 然后自动生成 sprite 然后 append to html (通过 JS)

有 2 个缺点

第一是 svg sprite 不能 cache, 因为它不是 .svg file 而是通过 js append 的. (它有 config 可以调生成 .svg file)

第二是它用 js import 来管理. 我理想中的应该是扫描 html 看有用到那个, 然后生成在 append .svg file 丫

参考: 

Generating an SVG Sprite Sheet with Webpack

Creating SVG sprites with Webpack using svg-sprite-loader

安装

yarn add svgo-loader --dev
yarn add svg-sprite-loader --dev

webpack.config

添加多一个 loader for svg. 可以特别指定路径. 之前 svg 是用 build-in 的 asset/resource 那个就拿掉.

注: extract: true 是做一个 .svg file 出来 (要 ajax 才会这样做), 如果只是 dev mode 就 set false 可以了, 它会自动 append svg sprite to html 的.

添加 plugin

在 ts import

import dada from '../fonts/svg-icon/google.svg'; // import 1 

function requireAll(r: __WebpackModuleApi.RequireContext): void { // import by folder
  r.keys().forEach(r);
}
requireAll(require.context('/src/fonts/svg-icon', true, /\.svg$/));

import svg 需要 type declaration, custom.d.ts

declare module '*.svg' {
  const content: unknown;
  export default content;
}

require.context 需要 @types/webpack-env

调用


  

当 js dom ready 后, 它就会把所有 import 的 svg 变成 sprite 然后 append svg to html. 这样上面的调用就有效了.

如果是用 extract 的话, 它就不会自动去 append svg sprite 了哦 (我也不知道为什么, 但教程的做法是用 ajax 去加载做 cache)

gulp-svg-sprite 使用

参考: gulp-svg-sprite 

npm install -g gulp
yarn add gulp --dev
yarn add gulp-svg-sprite --dev

gulpfile.js

const gulp = require('gulp');
const svgSprite = require('gulp-svg-sprite');

const config = {
  mode: {
    symbol: true,
  },
};

gulp.task('svgIcon', () => {
  return gulp
    .src('src/fonts/svg-icon/*.svg')
    .pipe(svgSprite(config))
    .pipe(gulp.dest('src/fonts/svg-icon-sprite'));
});

运行

gulp svgIcon

它出来的 folder 结构我不是很喜欢 (一定会有 symbol\svg), 但没有找到 config 可以调

调用

<svg style="width: 48px; height: 48px">
  <use xlink:href="../fonts/svg-icon-sprite/symbol/svg/sprite.symbol.svg#google" />
svg>

如果想用 CSS background image 的话, 它也是支持的, 但我没有研究

我目前的做法

下载 SVG 丢进一个 folder 然后用 gulp-svg-sprite 做优化和 sprite. 

如果下载的图片颜色不 ok 那就直接修改了才丢进去 folder.

Font Awesome

它有免费/付费版本. 到官网申请.

导入它的 script 放在 head, 它不是 CSS link 哦. 

<script
  src="https://kit.fontawesome.com/{your id}.js"
  crossorigin="anonymous"
>script>

调用

<i class="fab fa-facebook-square" style="font-size: 48px; color: red">i>

 它也是可以 download SVG 哦

通过 Yarn + Sass / JS

参考: 

Using webpack 5 with Font Awesome 5

How to make Font awesome 5 work with webpack

install

yarn add @fortawesome/fontawesome-free

import Sass

$fa-font-path: '~@fortawesome/fontawesome-free/webfonts';
@import '~@fortawesome/fontawesome-free/scss/fontawesome.scss';
@import '~@fortawesome/fontawesome-free/scss/solid.scss';

import JS

import '@fortawesome/fontawesome-free/js/fontawesome'
import '@fortawesome/fontawesome-free/js/solid'

Sass / JS 选其中一个就可以了.

使用

<i class="fas fa-shopping-cart" style="font-size: 48px; color: red">i>

局势

Icon 第一步是要先找到. 像 Material Icons, ionicons 这类 for App 的, icon 量很少. 不适合做网站.

fontawesome, flaticon, icons8 这些就很多选择, 但是大部分都收费. 

所以挺麻烦的. 比较中和的方法就是用一个免费的大库, 如果找不到 icon 就去各大平台找, 然后用 SVG 方式引入.

这个方法比较适合做 Web App, 做网站你要舒服建议就付费吧, 不然挺累的.

我现在的步骤是这样的:

SVG way: 

1. 找 icon (经常是这里找 SVG Repo)

2. 调颜色 (用这个 online tool BOXY SVG 或者改 fill=currentColor)

3. 做优化和 sprite sheet (用 gulp-svg-sprite)

4. 调用

Font way:

1. npm 下载库, 或者官网下载 woff2

2. import 或者 @font-face

3. 使用

相关