使用 SVG

Avatar of Chris Coyier
Chris Coyier 发布

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

SVG 是一种用于矢量图形的图像格式。它实际上代表 **可缩放矢量图形**。基本上,就是你在 Adobe Illustrator 中处理的内容。你可以在网页上非常轻松地使用 SVG,但有一些事项你需要了解。

为什么要使用 SVG?

  • 文件尺寸小,压缩效果好
  • 可以缩放至任意尺寸而不会损失清晰度(除了非常小的尺寸)
  • 在视网膜显示屏上看起来很棒
  • 设计控制,例如交互性和滤镜

使用 SVG

在 Adobe Illustrator 中设计一些内容。这里有一只站在椭圆形上的奇异鸟。

请注意,画板已裁剪到设计的边缘。画布在 SVG 中很重要,就像在 PNG 或 JPG 中一样。

你可以直接从 Adobe Illustrator 中将文件保存为 SVG 文件。

保存时,你将获得另一个 SVG 选项对话框。老实说,我对所有这些都不太了解。有一个关于 SVG 配置文件 的完整规范。我发现 SVG 1.1 运行良好。

这里有趣的部分是,你可以点击“确定”并保存文件,或者点击“SVG 代码…”,它将打开 TextEdit(在 Mac 上)并显示其中的 SVG 代码。

两者都很有用。

将 SVG 作为 <img> 使用

如果我将 SVG 保存到文件,我可以在 <img> 标签中直接使用它。

<img src="kiwi.svg" alt="Kiwi standing on oval">

在 Illustrator 中,我们的画板是 612px ✕ 502px。

这正是图像在页面上显示的大小,不受任何影响。但是,你只需选择 img 并更改其 widthheight 即可更改其大小,就像更改 PNG 或 JPG 一样。这是一个 示例

Check out this Pen!

浏览器支持

以这种方式使用它有自己的一套特定的 浏览器支持。基本上:除了 IE 8 及更低版本和 Android 2.3 及更低版本之外,其他所有浏览器都支持。

如果你想使用 SVG,但还需要支持不支持以这种方式使用 SVG 的浏览器,你可以选择其他方法。我在 不同的 研讨会 介绍了不同的技术。

一种方法是使用 Modernizr 测试支持并替换图像的 src

if (!Modernizr.svg) {
  $(".logo img").attr("src", "images/logo.png");
}

如果可以接受在标记中使用 JavaScript,David Bushell 有一个非常 简单的替代方案

<img src="image.svg" onerror="this.onerror=null; this.src='image.png'">

SVGeezy 也可以提供帮助。随着本文的继续,我们将介绍更多回退技术。

将 SVG 作为 background-image 使用

与将 SVG 作为 img 使用一样简单,你可以在 CSS 中将其用作 background-image

<a href="/" class="logo">
  Kiwi Corp
</a>
.logo {
  display: block;
  text-indent: -9999px;
  width: 100px;
  height: 82px;
  background: url(kiwi.svg);
  background-size: 100px 82px;
}

请注意,我们将 background-size 设置为 logo 元素的大小。我们必须这样做,否则我们只会看到我们更大的原始 SVG 图像的左上角。这些数字与原始尺寸的纵横比相关。但是,如果要确保图像适合并且无法知道父图像是否具有完全正确的尺寸,则可以使用 background-size 关键字(如 contain)。

浏览器支持

将 SVG 作为 background-image 使用有自己的一套特殊的 浏览器支持,但它与将 SVG 作为 img 使用基本相同。唯一有问题的浏览器是 IE 8 及更低版本和 Android 2.3 及更低版本。

Modernizr 可以在这里帮助我们,而且比使用 img 的方法更有效。如果我们将 background-image 替换为受支持的格式,则只会发出一个 HTTP 请求,而不是两个。如果浏览器不支持 SVG,Modernizr 会向 html 元素添加一个名为“no-svg”的类名,因此我们使用它。

.main-header {
  background: url(logo.svg) no-repeat top left;
  background-size: contain;
}

.no-svg .main-header {
  background-image: url(logo.png);
}

另一种巧妙的渐进增强风格技术是将 SVG 与多个背景一起使用。SVG 和多个背景具有非常相似的浏览器支持,因此如果浏览器支持多个背景,则它也支持 SVG,并且声明将起作用(并覆盖任何以前的声明)。

body {
  background: url(fallback.png);
  background-image: url(image.svg), none;
}

<img> 和 background-image 的问题…

是你无法像以下两种方法一样使用 CSS 控制 SVG 的内部内容。继续阅读!

使用“内联”SVG

还记得在保存时可以从 Illustrator 中获取 SVG 代码吗?(你也可以在文本编辑器中打开 SVG 文件并获取该代码。)你可以将该代码直接放入 HTML 文档中,SVG 图像将与将其放入 img 中一样显示。

<body>

   <!-- paste in SVG code, image shows up!  -->

</body>

这很好,因为图像直接出现在文档中,不需要发出额外的 HTTP 请求。换句话说,它具有与使用 数据 URI 相同的优势。它也具有相同的缺点。文档可能会“膨胀”,文档中有一大块垃圾,你试图创作,以及无法缓存。

如果你使用的是可以获取文件并插入文件的后端语言,至少可以清理创作体验。例如

<?php echo file_get_contents("kiwi.svg"); ?>

这里有一点 PHP 特定的内容……有人向我证明 file_get_contents() 是这里正确的函数,而不是我之前使用过的 include()include_once()。特别是因为 SVG 有时会导出 <?xml version="1.0" encoding="UTF-8"?> 作为开头行,这会导致 PHP 解析器出错。

先优化它

可能并不令人震惊,但 Adobe Illustrator 提供的 SVG 并不是特别优化。它具有 DOCTYPE 和生成器注释以及所有这些垃圾。SVG 本身已经很小了,但为什么不尽我们所能呢?Peter Collingridge 有一个在线 SVG 优化器 工具。上传旧的,下载新的。在 Kyle Foster 的视频中,他甚至更进一步,在优化后删除了换行符。

如果你更硬核,这里有一个 Node JS 工具 用于自己进行优化。

现在你可以使用 CSS 控制了!

看到 SVG 看起来很像 HTML 吗?这是因为它们本质上都是 XML(带有尖括号的命名标签,内部包含内容)。在我们的设计中,我们有两个组成设计的元素,一个 <ellipse> 和一个 <path>。我们可以进入代码并为它们提供类名,就像任何其他 HTML 元素都可以拥有类名一样。

<svg ...>
  <ellipse class="ground" .../>
  <path class="kiwi" .../>
</svg>

现在,在这个页面上的任何 CSS 中,我们都可以使用特殊的 SVG CSS 控制这些单个元素。这不必是嵌入在 SVG 本身中的 CSS,它可以位于任何位置,甚至在我们全局样式表中 <link>。请注意,SVG 元素有一组特殊的 CSS 属性可以在其上使用。例如,它不是 background-color,而是 fill。但你可以使用像 :hover 这样的普通内容。

.kiwi {
  fill: #94d31b; 
}
.kiwi:hover {
  fill: #ace63c; 
}

更酷的是,SVG 拥有所有这些花哨的滤镜。例如模糊。在你的 <svg> 中添加一个滤镜

<svg ...>
  ...
  <filter id="pictureFilter" >
    <feGaussianBlur stdDeviation="5" />
  </filter> 
</svg>

然后你可以在你的 CSS 中根据需要应用它

.ground:hover {
  filter: url(#pictureFilter);
}

这里有一个示例,展示了所有这些。

Check out this Pen!

浏览器支持

内联 SVG 有其自身的浏览器支持情况,但同样,它基本上只在 IE 8 及以下版本和 Android 2.3 及以下版本1中存在问题。

处理此类 SVG 回退的一种方法是

<svg> ... </svg>
<div class="fallback"></div>

然后再次使用 Modernizr

.fallback { 
  display: none;
  /* Make sure it's the same size as the SVG takes up */
}
.no-svg .fallback { 
  background-image: url(logo.png); 
}

使用 SVG 作为 <object>

如果“内联”SVG 不是你的菜(请记住它确实有一些合理的缺点,例如难以缓存),你可以链接到一个 SVG 文件并保留使用 CSS 影响其部分的能力,方法是使用<object>

<object type="image/svg+xml" data="kiwi.svg" class="logo">
  Kiwi Logo <!-- fallback image in CSS -->
</object>

对于回退,Modernizr 检测在这里可以正常工作

.no-svg .logo {
  width: 200px;
  height: 164px;
  background-image: url(kiwi.png);
}

这将非常适合缓存,并且实际上比以任何其他方式使用它具有更深的支持。但是,如果希望 CSS 样式起作用,则不能使用外部样式表或文档上的<style>,需要在 SVG 文件本身中使用<style>元素。

<svg ...>
  <style>
    /* SVG specific fancy CSS styling here */
  </style>
  ...
</svg>

用于 <object> SVG 的外部样式表

SVG 有一种声明外部样式表的方法,这对于创作、缓存等很有用。据我测试,这仅适用于<object>嵌入 SVG 文件。你需要将它放在 SVG 文件中,位于打开的<svg>标签之上。

<?xml-stylesheet type="text/css" href="svg.css" ?>

如果将其放在 HTML 中,页面将崩溃,甚至不会尝试渲染。如果链接到一个包含该内容的 SVG 文件作为<img>background-image,它不会崩溃,但也不会起作用(SVG 仍然会渲染)。

SVG 的数据 URL

使用 SVG 的另一种方法是将其转换为数据 URL。数据 URL 虽然可能不会节省实际的文件大小,但效率更高,因为数据就在那里。它不需要额外的网络请求。

Mobilefish.com 有一个在线转换工具用于进行 base64 编码,但我通常认为这对 SVG 来说不是一个好主意。只需粘贴 SVG 文件的内容并填写表单,它就会在文本区域中显示结果,以便你复制。请记住删除它返回的数据中的换行符。它看起来像纯乱码

你可以在我们之前讨论过的任何地方使用它(除了内联<svg>,因为这没有意义)。只需将乱码放在这些示例中 [data] 所在的位置。

这个转换器是我的最爱,因为它使 SVG 保持大部分可读文本

作为 <img>

<img src="data:image/svg+xml;base64,[data]">

作为 CSS

.logo {
  background: url("data:image/svg+xml;base64,[data]");
}

这里需要注意的是:常规 CSS 不在乎你是否在数据 URI 周围加引号,但 Sass 会,所以我上面加了引号(感谢 Oziel Perez)。

作为 <object>

<object type="image/svg+xml" data="data:image/svg+xml;base64,[data]">
  fallback
</object>

是的,如果在 base64 编码之前,SVG 中嵌入了<style>它仍然可以工作,如果你将其用作<object>

数据 URI 的格式

上面所有示例都使用 base64 作为编码,但数据 URI 不必是 base64。事实上,在 SVG 的情况下,最好不要使用 base64。主要是因为 SVG 的原生格式比 base64 的结果重复得多,它压缩得更好。

<!-- base64 -->
data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL...

<!-- UTF-8, not encoded -->
data:image/svg+xml;charset=UTF-8,<svg ...> ... </svg>

<!-- UTF-8, optimized encoding for compatibility -->
data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://...'

<!-- Fully URL encoded ASCII -->
data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A//...

用于 base64 编码 SVG 的命令行工具

或者,Mathias Bynens 有几种技术

使用openssl base64 < path/to/file.png | tr -d '\n' | pbcopycat path/to/file.png | openssl base64 | tr -d '\n' | pbcopy 跳过写入文件,只需将 base64 编码的输出复制到剪贴板,而无需换行符。

还有一个拖放工具

自动化工具

  • grunticon:

    从 CSS 的角度来看,它易于使用,因为它生成一个引用每个图标的类,并且不使用 CSS 精灵。

    grunticon 获取一个 SVG/PNG 文件夹(通常是你在 Adobe Illustrator 等应用程序中绘制的图标),并将它们输出到 3 种格式的 CSS 中:svg 数据 URL、png 数据 URL 和第三个回退 CSS 文件,其中包含对常规 png 图像的引用,这些图像也会自动生成并放置在文件夹中。

  • iconizr:

    一个 PHP 命令行工具,用于将 SVG 图像转换为一组 CSS 图标(SVG & PNG,单个图标和/或 CSS 精灵),并支持图像优化和 Sass 输出。

相关内容

Kyle Foster 的优化 SVG 工作流程,值得嵌入

…以及后续 + 幻灯片


1 说到 Android 2.3 浏览器,这个。但是,如果你必须支持原生浏览器,这个