SVG 是网站图标的最佳格式,毫无疑问。它允许您无论屏幕像素密度如何都能拥有清晰的图标,您可以在悬停时更改 SVG 的样式,甚至可以使用 CSS 或 JavaScript 动画图标。
在网页中包含 SVG 的方法有很多,每种技术都有其自身的优缺点。在过去几年里,我一直使用 Sass 函数在我的 CSS 中直接导入我的图标,避免弄乱我的 HTML 标记。
我有一个包含所有图标源代码的 Sass 列表。然后,每个图标都会使用 Sass 函数编码为数据 URI 并存储在网页根目录的 自定义属性 中。
TL;DR
我在这里提供给您的是一个 Sass 函数,它可以直接在您的 CSS 中创建 SVG 图标库。
SVG 源代码使用 Sass 函数编译,该函数将它们编码为数据 URI,然后将图标存储在 CSS 自定义属性中。您可以在您的 CSS 中随处使用任何图标,就像它是一个外部图像一样。
这是从我的个人网站代码中提取的一个示例
.c-filters__summary h2:after {
content: var(--svg-down-arrow);
position: relative;
top: 2px;
margin-left: auto;
animation: closeSummary .25s ease-out;
}
演示
Sass 结构
/* All the icons source codes */
$svg-icons: (
burger: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0...'
);
/* Sass function to encode the icons */
@function svg($name) {
@return url('data:image/svg+xml, #{$encodedSVG} ');
}
/* Store each icon into a custom property */
:root {
@each $name, $code in $svg-icons {
--svg-#{$name}: #{svg($name)};
}
}
/* Append a burger icon in my button */
.menu::after {
content: var(--svg-burger);
}
这种技术有利有弊,因此请在将此解决方案实施到您的项目中之前仔细考虑它们。
优点
- 没有针对 SVG 文件的 HTTP 请求。
- 所有图标都存储在一个位置。
- 如果需要更新图标,您无需查看每个 HTML 模板文件。
- 图标会与您的 CSS 一起缓存。
- 您可以手动编辑图标的源代码。
- 它不会通过添加额外的标记来污染您的 HTML。
- 您仍然可以使用 CSS 更改图标的颜色或某些方面。
缺点
- 您无法使用 CSS 动画或更新 SVG 的特定部分。
- 图标越多,编译后的 CSS 文件就越重。
我主要将此技术用于图标,而不是徽标或插图。编码的 SVG 始终会比其原始文件更重,因此我仍然使用外部文件(使用 <img>
标签或在 CSS 中使用 url(path/to/file.svg)
)加载复杂的 SVG。
将 SVG 编码为数据 URI
将您的 SVG 编码为数据 URI 并不新鲜。事实上,Chris Coyier 十年前就写了一篇文章介绍如何使用这种技术以及为什么要(或不应)使用它。
有两种方法可以在 CSS 中使用数据 URI 的 SVG
- 作为外部图像(使用
background-image,
border-image,
list-style-image,…) - 作为伪元素的内容(例如
::before
或::after
)
以下是一个基本示例,展示了如何使用这两种方法
此特定实现的主要问题是,您每次需要新图标时都必须手动转换 SVG,而且在 CSS 中拥有这种长长的不可读代码字符串并不令人愉快。
这就是 Sass 派上用场的地方!
使用 Sass 函数
通过使用 Sass,我们可以通过将 SVG 的源代码直接复制到我们的代码库中来简化我们的工作,让 Sass 正确地对它们进行编码,从而避免任何浏览器错误。
此解决方案主要受 Threespot Media 开发的现有函数的启发,该函数可在 他们的存储库 中找到。
以下是此技术的四个步骤
- 创建一个包含所有 SVG 图标的变量。
- 列出数据 URI 需要跳过的所有字符。
- 实现一个函数将 SVG 编码为数据 URI 格式。
- 在您的代码中使用您的函数。
1. 图标列表
/**
* Add all the icons of your project in this Sass list
*/
$svg-icons: (
burger: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24.8 18.92" width="24.8" height="18.92"><path d="M23.8,9.46H1m22.8,8.46H1M23.8,1H1" fill="none" stroke="#000" stroke-linecap="round" stroke-width="2"/></svg>'
);
2. 转义字符列表
/**
* Characters to escape from SVGs
* This list allows you to have inline CSS in your SVG code as well
*/
$fs-escape-chars: (
' ': '%20',
'\'': '%22',
'"': '%27',
'#': '%23',
'/': '%2F',
':': '%3A',
'(': '%28',
')': '%29',
'%': '%25',
'<': '%3C',
'>': '%3E',
'\\': '%5C',
'^': '%5E',
'{': '%7B',
'|': '%7C',
'}': '%7D',
);
3. 编码函数
/**
* You can call this function by using `svg(nameOfTheSVG)`
*/
@function svg($name) {
// Check if icon exists
@if not map-has-key($svg-icons, $name) {
@error 'icon “#{$name}” does not exists in $svg-icons map';
@return false;
}
// Get icon data
$icon-map: map-get($svg-icons, $name);
$escaped-string: '';
$unquote-icon: unquote($icon-map);
// Loop through each character in string
@for $i from 1 through str-length($unquote-icon) {
$char: str-slice($unquote-icon, $i, $i);
// Check if character is in symbol map
$char-lookup: map-get($fs-escape-chars, $char);
// If it is, use escaped version
@if $char-lookup != null {
$char: $char-lookup;
}
// Append character to escaped string
$escaped-string: $escaped-string + $char;
}
// Return inline SVG data
@return url('data:image/svg+xml, #{$escaped-string} ');
}
4. 在您的页面中添加 SVG
button {
&::after {
/* Import inline SVG */
content: svg(burger);
}
}
如果您按照这些步骤操作,Sass 应该正确编译您的代码并输出以下内容
button::after {
content: url("data:image/svg+xml, %3Csvg%20xmlns=%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox=%270%200%2024.8%2018.92%27%20width=%2724.8%27%20height=%2718.92%27%3E%3Cpath%20d=%27M23.8,9.46H1m22.8,8.46H1M23.8,1H1%27%20fill=%27none%27%20stroke=%27%23000%27%20stroke-linecap=%27round%27%20stroke-width=%272%27%2F%3E%3C%2Fsvg%3E ");
}
自定义属性
现在实现的 Sass svg()
函数运行良好。但它最大的缺陷是,如果代码中多个地方需要一个图标,就会被重复,从而可能大大增加编译后的 CSS 文件的体积!
为了避免这种情况,我们可以将所有图标存储在 CSS 变量 中,并使用对变量的引用,而不是每次都输出编码后的 URI。
我们将保留之前相同的代码,但这次我们将首先将 Sass 列表中的所有图标输出到网页的根目录
/**
* Convert all icons into custom properties
* They will be available to any HTML tag since they are attached to the :root
*/
:root {
@each $name, $code in $svg-icons {
--svg-#{$name}: #{svg($name)};
}
}
现在,我们不必每次需要图标时都调用 svg()
函数,而要使用以 --svg
为前缀创建的变量。
button::after {
/* Import inline SVG */
content: var(--svg-burger);
}
优化您的 SVG
此技术不会对您使用的 SVG 源代码进行任何优化。请确保您没有留下不必要的代码;否则它们也会被编码,从而增加您的 CSS 文件大小。
您可以查看 此很棒的工具列表,其中包含有关如何正确优化 SVG 的工具和信息。我最喜欢的工具是 Jake Archibald 的 SVGOMG - 只需将您的文件拖放到其中,然后复制输出的代码。
额外:在悬停时更新图标
使用此技术,我们无法使用 CSS 选择 SVG 的特定部分。例如,没有办法在用户将鼠标悬停在按钮上时更改图标的 fill
颜色。但是,我们可以使用 CSS 做一些技巧,以便仍然能够修改图标的外观。
例如,如果您有一个黑色图标,并且希望它在悬停时变为白色,您可以使用 invert()
CSS 过滤器。我们也可以使用 hue-rotate()
过滤器。
额外 #2:使用 CSS mask-image 属性更新图标
另一个可以更改图标颜色的技巧是将其用作伪元素的蒙版,该伪元素具有背景。将您的伪元素设置为 inline-block
,并具有 background-color
,并为所需大小定义 width
和 height
。
拥有具有所需颜色的矩形后,将这四个值应用于仅保留所需 SVG 形状。
mask-image: var(--svg-burger)
: 对我们图标的引用。mask-repeat: no-repeat
: 防止蒙版重复。mask-size: contain
: 使图标完美地适合矩形。mask-position: center
: 将我们的图标居中在伪元素中。
不要忘记,截至 2022 年 9 月,所有 CSS mask
属性仍然需要以 -webkit-
为前缀,才能在大多数浏览器中使用。
感谢 Christopher 和 Mike 在评论中告诉我这个技巧!
就是这样!
我希望您发现这个小助手函数在您自己的项目中很有用。请告诉我您对这种方法的看法 - 我很想知道您如何改进它或以不同的方式处理它!
我喜欢这种方法,它非常通用且井井有条。您甚至可以有一个构建步骤来引入一堆 SVG 并将它们编译成 Sass 文件。
对于自定义颜色,我通常将其视为一个带蒙版的元素,其背景设置为
currentColor
:https://codepen.io/chriskirknielsen/pen/jOxGObq有点脆弱,但我认为它在大多数情况下应该可以做到。
非常好
如果将 SVG 用作图像蒙版,则可以使用元素背景来满足所有着色需求。使悬停状态和网站主题变得更加容易:)
也一直在使用蒙版,并且在剪切路径上,因为它会正确地调整大小。但是,可能也存在缺点。
有意思。
谢谢,Louis!
Z。
我更喜欢使用
clip-path: path('your-svg-path-here');
不需要 XML…