我一直是图标字体的坚定支持者。许多网站确实需要一个图标系统,而图标字体提供了一个非常棒的系统。但是,我认为**假设您对 IE 9+ 满意**,使用内联 SVG 和<use>
元素来引用图标是一个更优越的系统。
首先,让我们了解一下它是如何工作的。
处理图标的一种好方法是在一个文件夹中保存一组 .svg
文件。

它们可以是彩色的,也可以是不彩色的,可以有多种形状、大小,等等。

您可以让 Illustrator(或其他软件)以任何方式保存它,包括所有附带的冗余信息。
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
<g>
<path d="M50.049,0.3c14.18,0.332,25.969,5.307,35.366,14.923S99.675,36.9,100,51.409c-0.195,11.445-3.415,21.494-9.658,30.146 - yadda yadda yadda"/>
</g>
</svg>
合并 .svg 文件
如果愿意,您可以手动执行此操作。我做过。您甚至不必查看最终文件。只需将其命名为 svg-defs.svg
或类似名称即可。
它应该只是一个 <svg>
标签,带有一个 <defs>
标签(这仅仅意味着您正在定义一些稍后要使用的内容),然后是一堆 <g>
(组)标签。每个 <g>
标签将具有一个唯一的 ID,并且会包装每个图标的所有路径等。
<svg>
<defs>
<g id="shape-icon-1">
<!-- all the paths and shapes and whatnot for this icon -->
<g>
<g id="shape-icon-2">
<!-- all the paths and shapes and whatnot for this icon -->
<g>
<!-- etc -->
</defs>
</svg>
同样,您可以手动执行此操作,但这有点繁琐。Fabrice Weinberg 创建了一个名为 grunt-svgstore 的 Grunt 插件来自动执行此操作。
如果您从未使用过 Grunt,您可以尝试一下。 这是一个入门教程视频。
您可以使用以下命令安装它:
npm install grunt-svgstore --save-dev
使用以下命令确保任务可用:
grunt.loadNpmTasks('grunt-svgstore');
然后在配置中:
svgstore: {
options: {
prefix : 'shape-', // This will prefix each <g> ID
},
default : {
files: {
'dest/svg-defs.svg': ['svgs/*.svg'],
}
}
}
},
在输出文件 svg-defs.svg
中,每个图标(来自源 .svg 文件的任何路径和内容)都将被包装在一个带有唯一前缀 ID 和文件名(不含 .svg)的 <g>
标签中,例如:
<g id="shape-codepen">
在文档顶部注入该 SVG
实际上包含它,例如:
<!DOCTYPE html>
<html lang="en">
<head>
...
</head>
<body>
<?php include_once("processed/svg-defs.svg"); ?>
或者您想如何执行此操作。
不幸的是,它必须位于顶部,因为 Chrome 中存在一个错误,如果稍后定义,此操作将无法正常工作。尽管……这个故事还有更多内容,因为在我键入这些文字时,本网站正在使用的主题在文档底部定义了图标,并且它可以正常工作。Ughkgh 令人困惑。
在任何地方使用图标
现在您可以在任何地方使用它们!例如:
<svg viewBox="0 0 100 100" class="icon shape-codepen">
<use xlink:href="#shape-codepen"></use>
</svg>
<symbol>
,因此您甚至不需要使用 viewBox!确保在 svg 上使用这些类名来调整其大小。
/* Do whatever makes sense here.
Just know that the svg will be an
enormous 100% wide if you don't
reign in the width. */
.icon {
display: inline-block;
width: 25px;
height: 25px;
}
太棒了:您可以使用 CSS 样式化它们(及其各个部分)
我们喜欢图标字体的其中一个原因是能够使用 CSS 对其进行样式化。此技术在这方面更胜一筹,因为我们可以在其中执行所有操作,甚至更多,因为
- 我们可以样式化所有单独的部分
- SVG 还有更多您可以控制的内容,例如特殊滤镜和笔划
svg 位于(某种程度上)DOM 中,因此 JavaScript 也可以。这里有一些样式化可能性以及所有这些工作的演示
查看 Chris Coyier 在 CodePen 上的笔 EBHlD (@chriscoyier)。
另一种方法:IcoMoon
IcoMoon 以生成图标字体而闻名,实际上也能够出色地生成 SVG 雪碧图。选择所有所需的字体后,点击底部的 SVG 按钮,您将获得该输出,包括一个使用内联 SVG 方法的演示页面。

浏览器支持
在浏览器支持方面,危险区域是 IE 8 及更低版本、Safari 5 及更低版本、iOS 4.3 及更低版本以及 Android 2.3 及更低版本。但是,如果您的策略是“最近两个主要版本”,那么您将获得几乎 100% 的支持。
请记住,图标只能用作辅助角色,例如始终伴随文字。如果是这种情况,支持并不是什么大问题。如果这些是独立的,并且不显示会导致网站无法使用,那将是一个大问题。
我可能会选择图标字体,因为那里的支持范围更广。只需确保您 正确地执行此操作。
这将变得更好
理想情况下,我们将能够做到这一点:
<svg viewBox="0 0 100 100" class="icon shape-codepen">
<use xlink:href="/images/svg-defs.svg#shape-codepen"></use>
</svg>
这在某些浏览器中确实有效,这意味着您可以跳过在文档顶部包含该文件。以这种方式执行此操作意味着额外的 HTTP 请求,但这意味着您可以更有效地利用缓存(而不是膨胀文档缓存)。在测试中,Jonathan Neal 发现您需要在 <svg>
上具有 xmlns 属性才能使其工作。
<svg xmlns="http://www.w3.org/2000/svg">
但即使这样,在任何 IE 中都不支持。**除非**您想用 <object>
替换整个 <svg><use>
,这确实有效。Jonathan Neal 再次 解决了这个问题
/MSIE|Trident/.test(navigator.userAgent) && document.addEventListener('DOMContentLoaded', function () {
[].forEach.call(document.querySelectorAll('svg'), function (svg) {
var use = svg.querySelector('use');
if (use) {
var object = document.createElement('object');
object.data = use.getAttribute('xlink:href');
object.className = svg.getAttribute('class');
svg.parentNode.replaceChild(object, svg);
}
});
});
他的演示 现在还有一种方法可以对内容发出 Ajax 请求并注入它,这使得填充可以在 IE 9 中工作。效率不高,但更像是 polyfill。
我想总有一天直接 <svg><use>
链接到 .svg 将成为首选方法。或者甚至可能是 <img>
使用 SVG 上的 URL 片段标识符。
浏览器将 <use>
视为 Shadow DOM

现在,我们可以使用 CSS 针对特定的 <path>
,例如:
.targetting-a-path {
fill: red;
}
但这会影响该路径的所有实例。您可能会认为您可以执行以下操作:
svg.shape-version-2 .targetting-a-path {
fill: red;
}
但这不起作用。它跨越了 Shadow DOM 边界。理想情况下,您将使用“帽子”选择器来打破它
svg.shape-version-2 ^ .targetting-a-path {
fill: red;
}
但该功能尚未得到支持,并且尚不清楚这是否正是它的工作方式。
“对比”图标字体
**基于矢量:**平局
**使用 CSS 样式化:**SVG 雪碧图略胜一筹(定位部分,SVG 特定样式,如笔划)
**奇怪的故障:**SVG 似乎可以正常工作(在受支持的情况下)。图标字体似乎会以奇怪的方式失败。例如,您将字符映射到普通字母,然后字体加载失败,您会得到大量随机字符。或者您映射到“专用区域”,某些浏览器会将其重新映射到 非常奇怪的字符,例如玫瑰,但很难复制。或者您想将 @font-face 文件托管在 CDN 上,但那是跨域的,Firefox 不喜欢它,因此您的服务器需要提供正确的跨域标头,但您的 Nginx 设置没有正确捕获它,唉。SVG 在这一点上胜出。
**语义:**这不是什么大问题,但我认为对于图像来说,<svg>
比 <span>
更合理。
可访问性:也许有人能告诉我?我们能否/应该为<svg>
添加一个标题属性或其他内容?或者在其中添加一个我们视觉上隐藏的<text>
元素?更新:<title>
元素可能有效。或者像这个SVG 可访问性规范中使用的那样,使用<desc>
元素。
易用性:像Fontello和IcoMoon这样的工具对于图标字体工作流程来说非常不错,但我认为,使用 Grunt 将一文件夹的 SVG 合并在一起的方法甚至更容易。
Ian Feather发布了一篇文章,讲述了他们为什么放弃图标字体,我同意他提出的每一个观点。
那是我想到的!Chris 偷走了我的荣誉 :D
我完全是从你那里学到的
<use>
!还记得https://css-tricks.org.cn/svg-tabs-using-svg-shape-template/吗?我从你那里学到了数百件事)谢谢 Chris!
谢谢你的这篇文章。
我认为值得补充一点,除了将 @font-face 图标映射到 PUA 或普通字母之外,还可以将其映射到类似的 Unicode 等效项。
结合使用时,可以获得相当不错的浏览器支持。
http://unicode.johnholtripley.co.uk/combined/
我认为吸引人们使用图标字体的一个重要原因是大量的图标集。对于无法自行设计图标的人来说,这一点非常重要。不过,我最近注意到更多优秀的 SVG 图标集。像你为字体图标做的那个一样,做一个 SVG 图标的汇总会很酷。
不要把它们想得那么不同。将图标字体字形更改为 SVG 文件非常容易。
1) 在 Illustrator(或其他软件)中创建一个新文档。
2) 激活图标字体。
3) 输入字符。
4) 转换为轮廓。
5) 另存为 .svg。
我将对目前可用的最佳 SVG 图标集进行一轮汇总。
有趣的文章。我喜欢图标字体,因为它们依赖于 SVG,这极大地有助于可伸缩性。
有一种巧妙的方法可以创建你自己的自定义字体图标,那就是访问此链接…
你的自定义字体
…并上传/拖动你的自定义 SVG 图标/字体。
谢谢你的这个链接。
我仍然更喜欢图标,因为我可以像文本一样对其进行样式设置,并与它们旁边的文本一起设置样式(颜色、阴影、行高)。这对于按钮的悬停效果特别有用,如果客户想要随意调整大小或重新着色,那也很容易。
当然,这确实取决于项目,并且精灵图比其他项目更适用于某些项目。
我刚开始使用 Grunt,当我尝试运行 Grunt 时出现以下错误。
正在加载“svgstore.js”任务…错误
我遇到了同样的问题——真的很想使用这个工具(正是我当前项目所需的),但 Grunt 似乎给我带来了一些问题。糟糕。
嘿,Terence,我试着解决这个问题,但还没有成功。你成功了吗?
没有成功——我设置了一个新的 Grunt 设置来测试它,没有任何其他内容运行,并且使用了最新版本的 Grunt,但仍然出现相同的错误。
有人知道解决方法吗?
抱歉,npm 包存在问题。
在 0.0.2 版本中已修复。
现在似乎出现了不同的错误——从…开始
尝试将 npm 更新到最新版本。
使用 IMG 标签并将 .svg 文件作为 src 的目标会产生什么影响?例如
<img src="my-icon.svg">
。我在 CodePen 上测试过以验证它是否有效(至少在 Chrome 中)。这样做有什么本质上的错误吗?这样做完全没有问题。我经常这样做。但是对于图标系统,你可能不希望为每个图标都这样做几十/数百次。目标是提高速度并减少 HTTP 请求,方法是只使用一个(或零个)包含所有字形的文件。
这里的主要目标是你可以使用 CSS 对图标进行样式设置。如果你使用标签,就会失去这种能力。第二个目标——当然是一个 HTTP 请求。
正如你指出的那样,在每次请求中内联包含整个精灵图并不是最佳做法。
将它包含在
<object>
标签中,并在页面加载时使用 JS 将子文档中的 SVG 元素复制到当前文档中,这样就可以使用<use>
元素来引用它们,怎么样?对于现实世界(非 CodePen)情况,实际上更容易做到这一点。只需将所有图标放入一个 SVG 文件中,并在 use 元素中引用文件名以及片段。就像任何其他由多个页面使用的图像资源一样,浏览器应该缓存 SVG 文件。
但如果你的“SVG 文件”实际上是到 CodePen 页面的链接,而不是实际的文件,则此方法无效。如果要链接到的文件与包含链接到它的
<use>
元素的文件不在同一域名下,则此方法在大多数浏览器(使用默认安全设置)中也无效。“域名、协议和端口必须匹配”,这是我的 Chrome 控制台中从我尝试构建的示例中出现的错误。很棒的技术。有人知道当 SVG 用作背景图像(可能与 background-size 结合使用)时,是否有任何方法可以进行这种“SVG 精灵图”操作吗?
你可以使用相同的 SVG 精灵图作为 background-image,但如果没有内联嵌入,你就无法使用 CSS 对 SVG 进行样式设置。
Robert 是正确的,不幸的是。但是确实存在一个效果相当不错的解决方法。请参阅Ian Feather 的文章,其中对这个问题进行了很好的解释。
我不喜欢尽管使用 SVG 的好处,但你仍然必须使用像素来指定图标尺寸。几周前我玩过 SVG 精灵图,并想出了一个有趣的解决方案。
我在这个精灵图生成包上测试过,效果非常好。
好吧,你不需要使用像素(尽管 CSS 像素始终在幕后存在)。你可以使用任何 CSS 单位(em、rem 等)来调整包装元素的大小,然后以百分比调整内部元素的大小。
Chris 的方法比你的 svg-as-css-bg 方法具有无可争辩的性能优势,因为在他的方法中,路径数据立即内联加载,而你的方法中,浏览器直到 CSS 加载并解析后才会请求 SVG 文件。背景图像通常最后到达——这可能正是你想要的,具体取决于你的优先级。
按照这种思路,我们不能仅仅对所有图像都使用 SVG 吗?
照片。
@Eric
但是,即使是照片和其他光栅图像也可以嵌入到 SVG 中以方便重新缩放。
所以……我们最终何时开始使用 SVG 进行所有布局并使用 foreignObject 用于内容?
可能性极低。使用 SVG 定位所有内容本质上与使用绝对值定位所有内容相同。尽管您可以嵌入自动调整大小的
foreignObject
元素(忽略当前实现的错误),但您无法轻松地(无需脚本)相应地调整其余布局。很棒的文章……
在显示样式化 SVG 图标的 CodePen 中……YouTube 图标的填充显示如下
.shape-youtube {
fill: url(#gradient);
}
…什么是 url(#gradient)……我找不到定义“#gradient”的地方……
谢谢,
找到了我问题的答案……它是一个 SVG 渐变……它在 HTML 中定义……
最好是在那里将渐变定义在
<defs>
块中,以及所有形状。我觉得应该可以工作,但实际上不行。因此,我将其移动到与<use>
相同的<svg>
中。从您的 CSS 中引用片段标识符可能会导致问题。Opera 和 FF 需要带有主 SVG 文件的路径 – url(icons.svg#element),而 Webkit 和 IE 只需要 el id –url(#element)。我们可以通过代码预处理然后有条件地加载 CSS 来使其工作,但这并不优雅。
在某些情况下,可能需要设置 xlink 的命名空间才能工作。它应该看起来像这样
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16">
这些 xmlns 有时真的很麻烦。
说得对。如果您需要在独立的 SVG 文件中使用
xlink:href
,则需要指定命名空间。当 SVG 代码内联在 HTML 5 文档中时,您可以跳过声明,因此很容易忘记。干得好,兄弟。你是大师。我是一个新手,想学习更多关于 CSS 和 SVG Sprites 的知识……
这太棒了!但是,将 SVG 添加到 HTML 中基本上意味着不会缓存 SVG(如果需要许多图标,SVG 文件可能非常大);但我认为有一个简单的解决方案
我们可以使用指向 SVG 文件的相对链接,后跟 ID。我创建了一个演示页面进行测试。它似乎在任何地方都能完美运行;但是,如果您在本地尝试,它会在 Chrome 中失败,并出现以下错误
托管在服务器上后,它将在 Chrome 中也能正常工作。这种方法解决了将 SVG 放入 HTML 中的缓存问题,并且使 HTML 也更加简洁。
在阅读本文后,我今天更新了 IcoMoon 的精灵生成器。如果您使用 IcoMoon 生成 SVG 精灵(使用SVG按钮而不是Font),它会将 SVG 放入 HTML 中,因为否则,演示在 Chrome 中无法在本地工作,这会令人困惑。所以,我希望找到一个适用于 Chrome 的解决方案。也许只是一个错误?
是的,我也看到了。我只是创建了一个本地域名来测试它,它工作正常。这与需要真实域名进行 Ajax 测试是一样的。
直接从
<use>
链接到 .svg 文件的真正缺点是它在任何 IE 版本中都无法工作。我用 Jonathan Neal 的一些似乎可行的内容更新了文章。查看他的演示:http://sandbox.thewikies.com/svg/值得一提的是,您可以使用 ajax 请求加载图标精灵文件,以便浏览器将其缓存。原生 js或JQuery
聪明!延迟加载并利用浏览器缓存,并停止文档缓存膨胀。
您是否碰巧知道此示例?我认为我理解该示例并想尝试一下,但我无法使用 PHP 加载 SVG 精灵文件,对我来说这不是一个选项。谢谢。
很棒的文章和见解——我将在我的下一个项目中尝试一下,并可能在此期间更新一些。
那就看看Iconmelon项目吧;) 它使用了相同的技术
很棒的文章。但我注意到 SVG 在手机上的响应速度较慢,因为渲染时间较长。在手机中包含图标的最佳解决方案是什么?Base64 编码?
看起来 :hover 样式无法用于更改填充颜色,无论目标是 svg 元素还是组。我是否遗漏了什么,或者这仅仅是 Shadow DOM 事件冒泡的胡言乱语?
您可以使用:hover 和其他伪类。
您可以使用样式将图标作为一个整体作为目标,但不能将其中的单个组件作为目标;在继承的样式未被更具体的样式覆盖的任何情况下,样式都将应用。
因此,您可以更改默认填充颜色和默认描边颜色(以及任何其他属性,如 fill-opacity 或 stroke-opacity),但图标中任何不使用默认值的部分都不会更改。您还可以利用这样一个事实,即您可以在 SVG 中使用关键字
currentColor
来获取对该元素有效的 CSScolor
属性的值,因此您可以使用它来创建您可以从 CSS 中控制的不同颜色的区域。此处演示
啊,我明白了。我试图用应用于
<svg>
的 CSS 规则覆盖我已经直接应用于<group>
的填充。那不好。可以使用此方法创建您的 svg。http://glyphter.com/
关于可访问性,是的,您应该使用
<title>
来获得与<img>
上的alt
相同的效果。“组合 .svg 文件”中的代码块中的 - 标签未关闭
嘿,Chris
还有一个生成 .png 的“polyfill”插件
http://svgmagic.bitlabs.nl/
我认为这比将 SVG 嵌入到对象中更优雅;)
最好的
Lucas Dechow
这是一个好主意!不幸的是,似乎不适用于内联 svg。我们必须对其进行分叉并添加此功能)
对于遇到此问题的任何人……
确保在您的 package.json 中指定 svgstore 的版本 0.0.2 以解决依赖项问题(即 chalk/cheerio 未定义)。
如果您随后遇到我遇到的问题(任务运行没有错误……但没有生成文件……),请在您的 gruntfile.js 中使用默认值,如下所示……
我找到的所有示例都直接进入
options{}
和files{}
,但在我的情况下,我必须将它们包含在default{}
中——最终通过检查 node_modules/svgstore 本身内的 gruntfile.js 解决了这个问题。糟糕。错过了上面代码中的一个花括号。使用
感谢 Chris。我没有使用GruntJS,而是使用gulp取得了一些不错的成果,使用了
gulp-svgmin
插件。您还可以使用
gulp-svg2png
插件自动生成旧版浏览器的 PNG 备用方案。如果您想变得更高级,还可以生成具有 8 位 Alpha 通道的 8 位 PNG。
我对编码比较陌生,不确定这种方法是否适用于 Opera 浏览器。我来这里是为了向你们学习 CSS 代码。继续努力,你们的一些技巧帮助我构建了我的网站。谢谢大家。
这里真正的痛点在于无法将 SVG 作为伪元素使用和设置样式。通常,图标纯粹是视觉上的,并被编码为 :before 和 :after。使用 SVG 时,我们必须将其作为背景图像,因此需要使用 CSS 设置样式的能力。
实际上,您可以像这样将 SVG 用作伪元素
我需要尝试一下使用 SVG 作为伪元素或背景图像时(defs、悬停样式等)的可能性。如果我们能够实现与内联 SVG 相同的控制级别,那就太棒了!
我理解您可以将它们用作背景图像,但正如我所说,您会失去设置 SVG 属性(即
fill
)样式的能力。这里有很多有趣的信息,感谢您与我们分享这些步骤!
我从未亲自测试过,但我一直听说使用 SVG 在某些浏览器中可能会导致性能大幅下降。有人可以确认吗?(或否认?)
这实际上取决于图像以及您将其与什么进行比较。某些类型的图形需要大型 PNG/JPEG 文件,但如果描述为 SVG,则可以非常紧凑,因此这对于下载和使用都是一个优势。它还取决于您将如何使用它。特别是 Firefox 似乎难以移动 SVG 图像——即使您根本没有更改图像,浏览器似乎也会每次都重新计算布局。如果使用一组 SVG 图标作为受背景位置属性控制的传统精灵图,则这是一个问题,也是使用内联 SVG 和
<use>
元素用于 SVG 图标的另一个原因。我同意 Amelia 的观点,这取决于您正在做什么。SVG 往往比纯光栅图像慢,但在许多情况下,与将 2 倍图像调整大小为 1 倍以适应高像素密度屏幕相比,它可能更快。根据我的经验,我使用本文中描述的技术启动了大约 4 个大型项目,并且从未遇到过问题。Christophe Schwyzer 进行了一些有趣的测试,您可能会感兴趣。
我的最新发现 - Iconizr http://github.com/jkphl/grunt-iconizr
用于自动化、完整周期 SVG 工作流的强大工具 - 通过 JS 加载器实现 SVG 精灵/dataURI/PNG 回退
甚至比 GruntIcon 更好!
为了实现可访问性,我喜欢使用带有为整个单词定义的连字的字体图标的想法。屏幕阅读器会将图标读作普通单词,甚至复制粘贴也会为您提供文本版本。对于简单的联系卡(带有电话、电子邮件等)来说,它可能非常巧妙。
当然,支持是另一回事。
这既很棒又很酷。但当我决定自己尝试时,我手动进行了合并(因为我喜欢这样做并且很容易搞砸终端),然后在 body 标记之后执行了 php 请求,就像 Chris 在上面所做的那样。图像加载到我想要的位置,但是文档顶部现在出现了一大块空白区域,其中包含了 svg 文件。我做错什么了吗?或者我是否遗漏了一些代码以防止 svg 文件作为一大块空间渲染到屏幕上?
通过添加 css 样式隐藏您的内联 svg 源代码。在 svg 标记上使用类似 style=”position: absolute; margin-left: -100%” 的样式应该可以正常工作。
可以通过 CSS 控制的 SVG 属性列表在这里。以防万一有人需要它。
很棒的文章!但是使用 transition css 属性进行动画怎么办?
过渡效果照常工作。
动画在不同浏览器之间无法正常工作,因此您可能需要使用 js 来为您的图标设置动画。
您不能在 FF 和 IE 中对 SVG 使用 CSS 变换,因此显然您也不能为它们设置动画和过渡。
Chris,
关于 defs 代码的位置,您写道
那么为什么它在 CSS-Tricks 中位于底部呢?
我做了一个 Pen作为个人测试。我认为如果对其他读者有帮助,我会发布它。我在 Illustrator 中创建了矢量,并将我想具有相同颜色的形状组合在一起,然后我命名了这些组,这些组变成了类名。这帮助我以图形方式了解我将哪些内容组合在一起。
grunt-svgstore 的 Gulp 等效项是gulp-svg-sprites。
在我的
src
文件夹中,我有一个装满 SVG 图标的文件夹。我使用defs: true
通过gulp-svg-sprites
运行它们,以在我的public
文件夹中生成一个sprite.svg
文件。然后我从我的src
文件夹中的 jade 模板生成 HTML,该模板在顶部包含 SVG 精灵注意:在不收到 Securi 错误的情况下,发布包含代码的评论确实很困难
似乎 SVG 图标无法像精灵或其他引用资源那样以相同的方式进行缓存。例如,如果我有 100 个不同的网页都使用同一组图标,我该如何避免将这些图标发送回浏览器 100 次?
此外,即使对于单个网页,如果任何部分都是动态创建的,浏览器也会在每次加载页面时都获取相同的静态 SVG。
如果您不需要支持 IE 任何版本,则可以执行
<use xlink:href="sprite.svg#icon>
,它将像其他任何内容一样被缓存。否则,是的,一些页面缓存膨胀,但至少对我来说,绝对不是一个障碍。有没有办法在不了解 viewBox 大小的情况下包含 SVG?
例如,
而不是
(然后使用 CSS 设置图标宽度/高度样式)
因为我的图标有几个不同的画布/viewBox 大小,并且在不输入 viewBox 的情况下包含它们会很方便/更快。
此外,似乎无法使用此方法定位 svg 的子元素?
如果我直接嵌入 svg,我可以只定位一条路径并使用 css 更改其填充,如果我采用上面所示的“use”方法,那么我似乎只能定位父元素,而不是子元素。
我错过了什么吗?
我真的很想让它工作……
抱歉,我刚刚重新阅读了关于 shadow-dom 的部分,它回答了我的问题。
令人沮丧的是,否则这种方法似乎很棒。可能只需要直接嵌入需要复杂功能的 SVG,并使用此方法来处理更简单的图标。
首先,非常感谢这篇精彩的文章。几年来我一直通过 compass 使用 png 精灵,我很高兴看到 svg 终于开始流行起来。
不过,我有点担心——当包含两个或三个图标时,这里没有性能问题,但是当你有一个包含 20-30 个 SVG 图标的雪碧图,并将它们全部作为标记包含在你的 HTML 中时……这不会导致严重的性能问题吗?
抱歉,没注意到
谢谢
非常感谢 Chris!这是一篇非常棒的文章!!
对于使用 Illustrator 创建 SVG 的用户 - 如果你在单独的图层上创建 SVG,则可以在 Illustrator 中安装一个脚本,该脚本允许你将图层导出为单独的 SVG。这使得我的工作流程更快。然后我将我的 SVG 上传到 Icomoon,然后生成 SVG 雪碧图而不是字体。
Chris,我完全同意你的观点,
“我想总有一天直接链接到 .svg 将是最佳选择。”
那将是太棒了,并且可以让事情更简洁!
文章说雪碧图必须包含在文档的顶部,紧跟在 body 标签之后,但注意到 CSS-Tricks 实际上将它们放在 body 的底部。那么哪个是对的呢?
我认为这里发生的事情是早期版本的 Chrome 有一个与此相关的问题。它们必须位于顶部,否则下面的 <use> 实例将失败。我记得确认过,但我现在记不起来了。所以要么是修复了,要么是我疯了。无论如何,我认为放在底部更好,因为它不会阻止渲染(可能)更重要的内容。
尽管如此,外部链接到它更好,我很快就会写一篇关于这方面的文章。
感谢回复。
你将如何进行外部链接,同时保持对 SVG 的样式设置能力并支持 IE?
我想我在这里遗漏了一些东西。
这种方法是否有明显的回退解决方案?
当系统中关闭字体抗锯齿时,图标字体也会失效。一些用户(像我一样)更喜欢没有抗锯齿的字体(为了保护眼睛),我甚至在浏览器中关闭远程字体渲染,因为许多网络字体在没有抗锯齿的情况下设计得很糟糕(我最喜欢的是 PT Sans,在两种情况下都能完美运行)。
在此设置中,一些图标字体无法显示正确的图标并显示方块。这可能是与浏览器渲染相关的(例如,Chrome 设法在某些网页上仍然正确显示基于字体的图标,而 Firefox 在大多数地方都失败了),但仍然……
Chris,我注意到你说你会写一篇关于如何将你的 SVG 外部链接的文章。你什么时候会讨论这个问题,我真的很想知道正确的方法是什么。在你的示例中,你使用 PHP 在顶部嵌入 SVG,如果你只使用 HTML 并且 PHP 不是选项,那么正确的方法是什么?
我看到你已经在下面的文章中回答了如何做到这一点。感谢你将这两篇文章放在一起。
更具体地说,我今天刚写了一篇关于如何使用外部源和(内联)SVG 的文章:https://css-tricks.org.cn/svg-use-external-source/
如果有人想要 Grunt 插件的 Gulp 版本,请查看这里:https://github.com/coma/gulp-svg-icons
它太棒了!
我计划在一个新项目中将 PNG 雪碧图切换到 SVG 雪碧图。我正在导出素材,一些简单的图标和一个来自 Illustrator CC 的徽标,发现文件大小非常大,我的意思是很大。整个 PNG 雪碧图只有 8KB。相同的 SVG 雪碧图是 3.5 Mb!!!导出为 PNG 时,单个图标的分数为 4 KB,而导出为 SVG 时为 40-50 KB。这太疯狂了。哎呀,我甚至尝试导出最简单的形状(一个带有颜色填充的普通正方形),它也占用了 4KB!
我假设我做错了什么,因为我发现这些大小不正常。但是我找不到是什么问题。导出选项看起来很正常,并且设置为最小值。
你的平均图标文件大小是多少?
进一步的研究显示了一个意外的行为:主画板大约是 1200×5000 像素。图标就位于其中。如果我尝试在适当位置导出图标(即删除主画板 > 通过双击使用画板工具将图标包装在其自己的画板中 > 然后将选定的画板导出为 SVG),结果是 3.5 MB 的图标。但是如果我这样做:将图标复制到主画板外部的任何位置 > 然后通过双击使用画板工具将图标包装在其自己的画板中 > 然后将选定的画板导出为 SVG。一切都很好,生成的图标小于 4KB。
这很奇怪,因为在这两种情况下,我最终都得到一个 60x60px 的单个画板,因此导出的素材应该大小相同。似乎 Illustrator 即使在画板不再存在的情况下,也正在导出原始的 1200×500 画板。
无论如何,我已经将这些问题移到了 Adobe 论坛。如果我找到更多信息,我会通知你……
我在 Illustrator 和 SVG 中遇到了很多麻烦。主要是确定合适的导出设置。如果我不保留 Illustrator 编辑功能来导出,则在重新打开 SVG 时,图形会乱七八糟。但是,如果我保持该设置,我就会得到一个更大的文件,该文件无法通过 svgo 进行优化。
从 Illustrator 导出 SVG 雪碧图后,我使用 Sublime Text 打开了 SVG 并剪切了许多不必要的冗余内容。我的 SVG 文件从大约 70k 变成了大约 40k。为了减小 SVG 文件大小,你可能需要做的一件事是减少图标的几何图形。这可能是统一、减去或创建项目轮廓的问题。此外,有时使用简化路径工具也有帮助。(显然,你必须小心,不要在此过程中破坏图标的保真度。)
一种快速了解是否正在减少几何图形的方法是转到保存 > svg > svg 代码并快速查看以查看是否减少了几何图形或增加了几何图形。此外,我减少 SVG 的另一种主要方法是在某些情况下,其中包含了 base64 编码的嵌入图像。也许有些人可以解释它们为什么在那里,但我删除了它们,并且没有看到删除它们带来的任何后果。
本文没有提到的是,如果你想使用 CSS 的
fill
属性来控制输出图标的颜色,则需要从编译后的 SVG 文件中删除所有内联fill="..."
实例。我尝试使用.icon-x { fill: red; }
但没有成功,因为我的 SVGsymbol
具有内联填充,这些填充覆盖了我的 CSS。希望有人发现这很有用。即使在最新最好的移动浏览器(例如 Android 4+、iOS 6+)上,SVG 片段标识符的支持也不好,是吗?我在两者中都看到了问题,其中元素根本无法一致显示;有时它们会出现,有时则不会。
不过我喜欢这项技术。假设我能找出导致我的图标显示间歇性缺失的原因,这是一个极好的解决方案。感谢分享!
我遇到一个有趣的错误(?),即如果你使用“defs”作为链接的一部分(例如图标)嵌入 SVG,则图标本身不会注册 jQuery 中的点击事件,但点击文本会触发。我认为这是由于 SVG 事件没有冒泡?
如果你直接嵌入 SVG,则无论你点击文本还是图标,链接都会触发。
我创建了一个简单的测试用例,可以在这里看到
http://codepen.io/greenchameleondesign/pen/tubJz
有趣的是,如果你使用 $(‘.element’).click(function(){ … }) 而不是 $(document).on(‘click’, ‘.element’, function(){ … }),它似乎会触发。
以防万一有人遇到同样的问题 - 它已被认定为 Chromium 错误,并将在未来的版本中修复。我想在 IE 中仍然存在问题 :/
https://code.google.com/p/chromium/issues/detail?id=382872
我尝试使用此技术进行实验。
我发现“在 Chrome 35 和 Firefox 29 上运行良好,但前提是链接文件在同一域名下,否则会被跨域策略阻止。
http://codepen.io/denilsonsa/pen/vdeLu
嘿 Chris,对我来说,php include_once 命令不起作用。
我该怎么办?