前端图标解决方案

1. 前言

随着 Web 技术的发展与日益丰富的界面需求,图标逐渐成为前端开发中不可或缺的一部分,为此也诞生了各种各样的解决方案。文章总结及分析了目前常见的一些图标解决方案。

2. CSS 背景图片

2.1 background-image

图标本质上也是图片,所以一种最简单的方式就是利用background-image将图片作为图标容器的背景,例如:

css
复制代码
.icon {
  background-image: url("demo.jpg");
}

但是一个页面里往往会有很多图标,如果每个图标都去请求一次图片,会导致 HTTP 请求数量较多,我们知道 HTTP 并发请求数量是有上限的(例如 Chrome 最大是 6,HTTP/2 没有并发限制,此处暂且不论),请求太多图片会导致后面加载的图片被前面的图片阻塞,进而降低整体响应时间。为了解决这个问题,我们可以使用图像合并技术(Image Sprites)。

2.2 CSS Sprites

图像合并技术的原理是将多个图片合并成一个图片,使用时获取该图片的部分内容。这种做法有效减少了图片的请求数量,刚好适合图标的应用。

CSS Sprites(精灵图,雪碧图) 就是利用 CSS 背景图片实现图像合并的技术,图像合并可以使用其他方式,图像的部分获取主要是使用background-position配合background-image实现。例如,假设有一张 100px * 50px 的合并图片cat.png

sprites.png

展示左边的笑脸猫可以使用:

css
复制代码
/* 笑脸猫 */
.icon1 {
  width: 50px;
  height: 50px;
  background-image: url("cat.png");
  background-position: 0 0; /* 不偏移 */
}

展示右边的傲娇猫可以使用:

css
复制代码
/* 傲娇猫 */
.icon2 {
  width: 50px;
  height: 50px;
  background-image: url("cat.png");
  background-position: -50px 0; /* 向左偏移 50px */
}

实际使用时可以将公共的部分提取出来,不同的图标只需改变background-position

css
复制代码
.icon {
  width: 50px;
  height: 50px;
  background-image: url("cat.png");
}
.icon1 {
  background-position: 0 0; /* 不偏移 */
}
.icon2 {
  background-position: -50px 0; /* 向左偏移 50px */
}

根据 CSS Sprites 的原理,容易得出与其相关的一些结论:

  • 适用于固定容器尺寸:对于一个合并图像,每个图标的尺寸是固定的,如果一个图标要适应较多的容器,就会产生一些问题:

    • 图标尺寸 = 容器尺寸:最佳状态;
    • 图标尺寸 < 容器尺寸:图标可能失真;
    • 图标尺寸 > 容器尺寸:配合background-size可以兼容所有情况,但是整个合并图像尺寸会比较大,导致请求速度较慢。

    实际使用中可以设计多套不同尺寸的图标使用,但是维护成本也会相应增加。

  • 适用于不需要频繁更改的场景:图片文件的维护成本相对较高,频繁新增,更改,甚至删除都会极大增加维护成本,如果是多套不同图标,维护会更困难。

  • 图标颜色是固定的,不能随意更改。

  • CSS 计算图标位置时很容易出错,最好借助三方工具去设计,比如 CSS Sprites Generator。

3. 字体图标

3.1 字体图标介绍

字体图标是另一种常见的图标解决方案,其基本原理是将一组图标(例如 SVG 文件)打包成一种字体,将该字体加载到网页后,使用与某个图标对应的 Unicode 字符编码去显示该图标。例如在图标库Material Design Icons(mdi) 中,如果要显示一个 account 图标:

account.svg(2).png

需要以下两步:

  1. 使用@font-face加载字体:
css
复制代码
@font-face {
  font-family: "Material Design Icons";
  src: url("materialdesignicons-webfont.woff2"); // 路径应替换成字体文件路径
}
  1. 引用字体:

根据 mdi 文档,account 图标对应的字符编码是U+F004,在 HTML 中可以这样引用:

html
复制代码
<!-- &#xF004 是 U+F004 在 HTML 中的表示方法 -->
<span style="font-family: 'Material Design Icons'">&#xF004</span>

实际中因为字符编码使用不便,一般会在 CSS 中定义一些类:

css
复制代码
/* 公共类,所有图标都依赖该类 */
.mdi {
  font-family: 'Material Design Icons';
}
/* account 定制类,\F004 为 U+F004 在 CSS 中的表示方法 */
.mdi-account::before {
  content: '\F004';
}

在 HTML 中,只需要使用<span class="mdi mdi-account"></span>即可显示 account 图标。

3.2 字体图标分析

相比 CSS Sprites 来说,字体图标有不少优势,如:

  • 可以适应不同容器尺寸。
  • 可以自由更改图标颜色。
  • 使用与维护要比 CSS Sprites 方便很多。

当然了,也会有一些劣势:

  • 只能使用纯色图标,对彩色图标无能为力。

字体图标还有一个很大的问题,公共的图标库(如 mdi)为了满足各种各样的需求都会有很多图标,我们的项目并不会全部使用,这样在前端打包的时候就会浪费很多空间,导致页面首屏加载速度减慢。

为了解决这个问题,我们可以尝试在字体打包阶段介入(毕竟即使可以处理字体中的 CSS,也无法解决字体文件过大的问题)。字体打包实际上就是将一系列图标文件转化为了字体文件与字体样式,如果我们能够控制转换的过程以及转换的目标,这个问题就可以解决。仍以 mdi 图标为例:所有的 mdi 图标存放在@mdi/svg包,mdi 打包过程可以使用@mdi/font-build包实现,这个包可以指定需要转换的图标以及最终的字体格式。如果我们能够搜集到应用中所有使用到的图标(很不舒服的一点是这一步只能手动检索),那么我们就可以控制最终的字体文件大小。

另外,我们也可以控制最终生成的字体格式,实际上,现代浏览器很多已经支持了woff2格式,因此如果不需要兼容很早的浏览器,完全可以只引用woff2字体(woff2字体具有更小的尺寸)。当然了,我们可以根据需求进行调整,浏览器对字体格式的支持程度如下:

  • woff2:caniuse.com/?search=wof… 推荐,需要考虑兼容性。
  • woff:caniuse.com/?search=wof… 推荐,已经被绝大部分浏览器支持了。
  • ttf/otf:caniuse.com/?search=ttf 不推荐。
  • eot:caniuse.com/?search=eot 不推荐,只有 IE 支持。

4. SVG 图标

4.1 内嵌 SVG

SVG 能够绘制矢量图,在不同的容器尺寸下不会有失真的情况,将 SVG 直接嵌入在 HTML 中即可使用,例如:

html
复制代码
<div style="width: 50px; height: 50px;">
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
    <path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"/>
  </svg>
</div>

即可画出:

account.svg(2).png

相比字体图标来说,内嵌 SVG 可以渲染彩色图标,这是一个较大的优势,但是这种方案也有一个问题,就是如果同一个图标使用了很多次,需要重复很多相同的 SVG,从代码层面上我们可以使用变量去存储,但是 HTML 解析的时候还是会重复解析。为了解决这个问题,我们可以使用 SVG Sprites。

4.2 SVG Sprites

类似于 CSS Sprites,SVG Sprites 就是将多个 SVG 合并到一个 SVG 文件中,在引用的时候将需要的 SVG 内容取出,从而达到复用 SVG 的目的。其基本做法是利用 SVG <symbol> 元素定义图标,然后使用<use>元素引用图标。例如,有一个 account 的 SVG 图像如下:

svg
复制代码
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z" />
</svg>

我们可以使用<symbol>元素将其定义在一个sprites.svg的文件中:

svg
复制代码
<!-- sprites.svg -->
<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="account" viewBox="0 0 24 24"> <!-- 使用 account id 标识该图标 -->
    <path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"/>
  </symbol>
</svg>

在 HTML 中可以这样使用:

html
复制代码
<div style="width: 50px; height: 50px;">
  <svg viewBox="0 0 24 24">
    <!-- 引用该图标(文件名#ID) -->
    <use xlink:href="sprites.svg#account"></use>
  </svg>
</div>

这样就可以正确绘制出 account 图标了。

结合以上的图标方案可以看出 SVG Sprites 几乎可以支持各种类型的图标,在其他方案解决不了的情况下可以考虑这种,如果图标不是很多,也可以直接嵌入 SVG。当然了,使用 SVG Sprites 的时候也需要关注下浏览器兼容性:

  • <symbol>:caniuse.com/?search=svg…
  • <use>:caniuse.com/?search=svg…

5. CSS 绘制

图标的另一个解决方案是直接使用 CSS 绘制,这种方案利用 CSS borderbox-shadowtransform等属性结合伪元素beforeafter拼出图标,使用的时候直接引用相应的类名即可,具体做法可以参考 css.gg/ 。

这种做法的优势是使用方便,还能够使用animation支持动态图标,劣势是图标库的设计较为复杂,只能使用一些简单的图标,如果过于复杂,实现起来会比较困难,即便可以实现也会有大量的 CSS 代码,使用的时候需要综合考虑。

6. 小结

本文总结了前端开发中常见的一些图标解决方案,并分析了不同解决方案的优劣势。目前比较主流的方案是字体图标和 SVG 图标,CSS Sprites 和 CSS 绘制可以在特定场景下使用。

学习更多前端知识请关注CRMEB

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/44446.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人才公寓水电表改造解决方案

随着社会经济的不断发展&#xff0c;人才公寓作为吸引和留住人才的重要配套设施&#xff0c;其水电表改造问题越来越受到人们的关注。本文将从以下几个方面探讨人才公寓水电表改造解决方案。 一、现状分析 目前&#xff0c;人才公寓的水电表普遍存在以下几个问题&#xff1a; …

科技资讯|苹果计划本月推出Vision Pro头显开发套件,电池有重大更新

根据消息源 aaronp613 分享的信息&#xff0c;苹果计划本月底面向开发者&#xff0c;发布 Vision Pro 头显开发套件。消息源还指出苹果更新了 Vision Pro 头显电池组的代号&#xff0c;共有 A2781&#xff0c;A2988 和 A2697 三种不同的型号&#xff0c;目前尚不清楚三者之间的…

【iOS】多界面传值

文章目录 前言一、属性传值二、协议传值三、block传值四、KVO传值五、KVO的自动触发与手动触发六、通知传值总结 前言 在写网易云音乐以及3GShare包括后面的学生管理系统时&#xff0c;用到许多界面传值方法&#xff0c;特撰写博客记录目前学过的几种多界面传值方法 一、属性…

了解Unity编辑器之组件篇Video(二)

Video Player组件&#xff1a;用于在游戏中播放视频的组件。它提供了一系列属性来控制视频的播放、显示和交互。 1.Source&#xff08;视频源&#xff09;&#xff1a;用于指定视频的来源。可以选择两种不同的视频源类型&#xff1a; &#xff08;1&#xff09;Vieo Clip&#…

STM32 点灯实现 7.18

嵌入式&#xff1a; 以应用为中心&#xff0c;以专用计算机为基础&#xff0c;软硬件可裁剪ARM A系列芯片&#xff1a;高端芯片&#xff0c;实现人机互动 R系列&#xff1a;实现时效性 M系列&#xff1a;低端芯片&#xff0c;控制硬件设备&#xff0c;灯&#xff0c;风扇....…

设备监测诊断与维护:优化工业生产效率的关键措施

在现代工业生产中&#xff0c;设备的稳定运行对于保障生产效率至关重要。设备监测、诊断和维护作为关键措施&#xff0c;能够帮助企业及时发现设备问题、诊断故障原因&#xff0c;并采取有效维护措施&#xff0c;从而降低生产中断风险&#xff0c;提高生产效率。本文将深入探讨…

Verilog 学习之路二——基础学习总结(摘取自菜鸟教程)

目录 1 Verilog 设计方法2. 基础语法2.1 格式2.2 数值表示数值种类表示方法 2.3 数据类型2.4 表达式 3. 编译指令4. 连续赋值5. 过程结构6 过程赋值7 时序控制8 语句块9 循环10 函数例子-数码管译码 1 Verilog 设计方法 Verilog 的设计多采用自上而下的设计方法&#xff08;to…

平台化的测试工具推荐|一站式测试平台RunnerGo

互联网行业的发展到今天越来越多的公司更加注重工作效率和团队协作&#xff0c;越来越多的产品也趋于平台化&#xff0c;平台化也更有利于提高团队效率&#xff0c;代码管理、持续构建、持续部署这些工具的发展都是非常超前的&#xff0c;它们对于团队协作的支持和工作效率的提…

vue中如何通过webpack-bundle-analyzer打包分析工具进行配置优化

vue中随着项目的不断功能迭代和开发&#xff0c;项目文件越来越多&#xff0c;项目的打包文件也越来越大。如何对打包文件进行分析优化&#xff0c;减小打包文件大小呢&#xff1f;可以通过webpack-bundle-analyzer 这个打包分析工具进行解决。 1、webpack-bundle-analyzer的安…

接口漏洞-WebService-wsdl+SOAP-Swagger+HTTP-WebPack

什么是接口&#xff1f; 接口就是位于复杂系统之上并且能简化你的任务&#xff0c;它就像一个中间人让你不需要了解详细的所有细节。像谷歌搜索系统&#xff0c;它提供了搜索接口&#xff0c;简化了你的搜索任务。再像用户登录页面&#xff0c;我们只需要调用我们的登录接口&am…

【go语言学习笔记】02 Go语言高效并发

文章目录 一、并发基础1. 协程&#xff08;Goroutine&#xff09;2. Channel2.1 声明2.2 无缓冲 channel2.3 有缓冲 channel2.4 关闭 channel2.5 单向 channel2.6 selectchannel 示例 二、同步原语1. 资源竞争2. 同步原语2.1 sync.Mutex2.2 sync.RWMutex2.3 sync.WaitGroup2.4 …

TypeError: can‘t convert np.ndarray of type numpy.object_.

在处理数据集的时候出现报错&#xff1a; TypeError: can’t convert np.ndarray of type numpy.object_. The only supported types are: float64, float32, float16, complex64, complex128, int64, int32, int16, int8, uint8, and bool. train_labels torch.tensor(train…

ES6基础知识七:你是怎么理解ES6中 Generator的?使用场景?

一、介绍 Generator 函数是 ES6 提供的一种异步编程解决方案&#xff0c;语法行为与传统函数完全不同 回顾下上文提到的解决异步的手段&#xff1a; 回调函数promise 那么&#xff0c;上文我们提到promsie已经是一种比较流行的解决异步方案&#xff0c;那么为什么还出现Gen…

Docker安装Nexus并配置Maven私服

1 准备工作 1 服务器已安装docker, docker各命令无报错 2 通过dockerhub查看nexus的版本信息&#xff0c;此次使用的镜像为&#xff1a;sonatype/nexus3&#xff0c;可以看到latest版本更前的的是3.58.0&#xff0c;我们这次就使用这个版本的nexus3. 2 开始安装 # 下载镜像 do…

Java中的队列

队列的理解 队列&#xff08;Queue&#xff09;是一种特殊的线性表&#xff0c;它只允许在表的前端进行删除操作&#xff0c;而在表的后端进行插入操作。 LinkedList类实现了Queue接口&#xff0c;因此我们可以把LinkedList当成Queue来用。 常用方法 实例 import java.util…

Go基础快速入门

目录 一、变量相关基础语法 1、变量的定义以及赋值 2、变量的交换 3、匿名变量 4、变量的作用域 二、常量 三、基本数据类型 1、常见数据类型 2、数据类型的转换 四、运算符 五、函数 函数高级用法 函数也是一个类型 函数也是一个变量&#xff0c;也可以赋值 高…

Jmeter接口自动化生成测试报告html格式

jmeter自带执行结果查看的插件&#xff0c;但是需要在jmeter工具中才能查看&#xff0c;如果要向领导提交测试结果&#xff0c;不够方便直观。 笔者刚做了这方面的尝试&#xff0c;总结出来分享给大家。 这里需要用到ant来执行测试用例并生成HTML格式测试报告。 一、ant下载安…

Opencv 细节补充

1.分辨率的解释 •像素&#xff1a;像素是分辨率的单位。像素是构成位图图像最基本的单元&#xff0c;每个像素都有自己的颜色。 •分辨率&#xff08;解析度&#xff09;&#xff1a; a) 图像分辨率就是单位英寸内的像素点数。单位为PPI(Pixels Per Inch) b) PPI表示的是每英…

【stm32L152】段码屏驱动注解、MX_LCD_Init()初始化失败的解决方法

文章目录 断码屏驱动补充MX_LCD_Init()驱动初始化失败 断码屏驱动补充 已经有大神写过较详细的教程&#xff1a;https://blog.csdn.net/CSDN_Gao_16/article/details/115463499&#xff0c;但这篇博文仍然比较抽象&#xff0c;我看了好多遍才看明白-_-||&#xff0c;为了节省和…

选择最佳安全文件传输方法的重要性

在数字化时代&#xff0c;文件的传输是商务、教育、科研、医学等领域不可或缺的工作流程。为了保障数据安全&#xff0c;选择最佳安全文件传输方法非常关键。在本文中&#xff0c;我们将探讨选择最佳安全文件传输方法的重要性。 第一、最佳安全文件传输方法可以保证文件内容不被…