乐趣区

SVG的正确使用姿势

原文地址: https://css-tricks.com/using-…

原文作者: Chris Coyier

翻译作者: https://github.com/chenmf6

翻译出处:https://github.com/lightningm…

SVG 是一种向量图的图片格式,即 可伸缩向量图(Scalable Vector Graphics),可以在 Adobe Illustrator 里面生成。在 Web 中使用 SVG 很简单,但是也有一些需要知道的事情。

为什么用 SVG

  • 压缩后文件体积小
  • 可以无损伸缩到任意尺寸(除非尺寸特别小)
  • 在 retina 屏幕上可以完美显示
  • 设计可控,比如交互和滤镜

怎么生成 SVG

可以在 Adobe Illustrator 里设计并且得到 SVG。下面是一个站在椭圆上的奇异鸟:

留意到画板刚好贴着设计主体的边缘,画布的大小在 SVG 里面的重要性和在 PNG 和 JPG 里面是一样的。
然后可以直接在 Adobe Illustrator 里面保存成 SVG 文件。

保存的时候,可以在 duihua 对话框里面选择 SVG 选项。完整的参考可以看 SVG 介绍。这里选 SVG 1.1 就可以了。

当点击 ’OK’ 或者 ’SVG Code…’ 的时候,就会打开文本编辑器,显示 SVG 的编码。

<img> 标签里面使用 SVG

如果把 SVG 保存成文件之后,可以直接在 <img> 标签里面使用。

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

在 Illustrator 里面,画板的大小是 612px ✕ 502px:

这正是图片在页面中的大小。可以选择 <img> 标签并且改变 widthheight来改变它的尺寸,就像 PNG 和 JPG 一样,比如:

前往 codepen 查看

浏览器支持

<img> 标签里面使用需要有浏览器支持。基本上在 IE8 以上和 Android 2.3 以上都可以用。
如果你想要在不支持的浏览器里面使用,可以这样:

  1. 使用 Modernizr 来替换 <img>src属性:
jQuery

if (!Modernizr.svg) {$(".logo img").attr("src", "images/logo.png");
}
  1. David Bushell 提供了一个更简单的操作:
HTML

<img src="image.svg" onerror="this.onerror=null; this.src='image.png'">
  1. 使用 SVGeezy

background-image 里面使用 SVG

可以在 CSS 的 background-image 里面使用 SVG。

HTML

<a href="/" class="logo">
  Kiwi Corp
</a>
CSS

.logo {
  display: block;
  text-indent: -9999px;
  width: 100px;
  height: 82px;
  background: url(kiwi.svg);
  background-size: 100px 82px;
}

注意把 background-size 设置成我们想要的尺寸,否则只能看到很大的原始 SVG 图片的左上角。这个尺寸设置成了跟原始尺寸保持宽高比,如果在不知道原始尺寸的情况下想要保持宽高比,可以把 background-size 设置成contain

浏览器支持

background-image 里面使用 SVG 也需要看浏览器支持,基本上跟在 <img> 中使用是一样的。

如果要在不支持的浏览器里面使用:

  1. 用 Modernizr 把 background-image 替换成一个支持的格式。它会在不支持 SVG 的情况下加上一个 no-svg 的 class,注意它也是只会发送一个图片的 HTTP 请求,不会发两个。
CSS

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

.no-svg .main-header {background-image: url(logo.png);
}
  1. 另一个更方便的方法,就是利用多个背景(background),SVG 的浏览器支持和多背景的很接近。
CSS

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

使用 <img>background-image的问题

<img>background-image里面使用 SVG,没法利用 CSS 对 SVG 内部进行控制,所以接着看下面的两种其他方式。

使用内联(inline)SVG

在保存 SVG 的时候可以获取 SVG 的代码(也可以直接在文本编辑器里面打开 SVG 文件),直接把 SVG 的代码复制到 HTML 里面:

HTML

<body>

   <!-- 把 SVG 的代码复制到这里就可以显示图片了  -->

</body>

这样做的好处是把图片的内容直接写在文档里面,不需要额外发送 HTTP 请求获取,它和使用 Data URI 的好处是一样的,坏处也一样:导致文档变得臃肿,难以抓取和缓存。

如果使用后端语言的话,可以获取文件并且插入到文档:

PHP

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

说到 PHP,这里用 file_get_contents() 方法比较合适,而不是 include()include_once(),因为 SVG 有时候会以 <?xml version="1.0" encoding="UTF-8"?> 开头,导致 PHP 编译有问题。

先优化 SVG

Adobe Illustrator 里面导出的 SVG 可能不是最优的,会包含一些冗余信息,比如 DOCTYPE 和生成信息。我们可以进一步优化,减少体积。Peter Collingridge 给出了在线的 SVG 优化,把需要优化的 SVG 上传,然后下载新的就可以了。
如果你是硬核玩家,可以直接用这个 NodeJS 工具自己优化。

用 CSS 来控制 SVG

SVG 的代码看起来是不是很像 HTML?因为它们都是基于 XML 的。我们的 SVG 里面包含了两个元素:<ellipse><path>,可以直接在代码里面给它们加上 class,就像 HTML 元素一样:

SVG

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

然后就可以用特殊的 SVG CSS 来控制这些元素了。SVG 元素由着特殊的 CSS 属性,比如它没有background-color,而是用fill,但是也可以使用一些其他的普通属性,比如:hover

CSS

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

更厉害的是,SVG 可以使用滤镜(filter),比如模糊滤镜。比如在 SVG 代码里面可以加上一个滤镜:

SVG

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

然后可以在 CSS 里面使用这个滤镜

CSS

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

下面是一个完整的例子:

前往 codepen 查看

更多阅读:

  • SVG 滤镜的更多应用
  • SVG CSS 属性大全(针对 Opera)
  • SVG 滤镜效果演示(由 Microsoft 提供)

浏览器支持

内联 SVG 的浏览器支持看这里,基本和前面的一样。兼容的方法:

HTML

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

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

<object> 里面使用 SVG

如果想要通过 CSS 控制 SVG,但是又想避免内联 SVG 的弊端,可以在 <object> 里面使用 SVG。

HTML

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

同样可以使用 Modernizr 来兼容:

CSS

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

这种情况下,如果想要用 CSS 控制 SVG,就不能用外部的样式或者文档里面的 <style> 了,要用 SVG 文件内部的<style>:

SVG

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

<object> SVG 里使用外部样式

可以在 SVG 文件开头的 <svg> 标签前面引入:

HTML

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

如果把这个放在 HTML 里面,页面会崩溃没法渲染,如果把这个放在 <img> 或者 background-image 的 SVG 里面,页面不会崩溃,但是也不起作用。

在 Data URL 里面使用 SVG

还可以把 SVG 转换成 Data URL,转换之后可能不止原来的文件大小,但是它很方便,因为不需要额外产生网络请求。
Mobilefish.com 上面有一个 base64 在线转换器,可以转成 base64 编码,但是这种方式不太推荐。记得去掉换行:

它可以在上述的所有场景里面使用,除了内联 SVG。

个人比较推荐这个在线转换器,因为转换之后可读性比较强。

  • 用在 <img> 里面
HTML

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

.logo {background: url("data:image/svg+xml;base64,[data]");
}
  • <object>里面
HTML

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

如果,SVG 在 base64 编码之前有嵌套的 <style>,那么它依然可以在<object> 里面起作用。

Data URI 格式

上面的例子都是 base64 编码的,但是也不一定要转换成 base64 编码,实际上对于 SVG 最好不要转成 base64 编码。因为 SVG 的原始格式文本重复性比较高,gzip 压缩效果更好。

HTML

<!-- 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//...

自动化工具

  • grunticon

从 CSS 的角度来看比较易用,为每个 icon 生成一个 class,不用 CSS sprites。grunticon 输入一个 SVG/PNG 文件的目录,然后输出对应的 3 种格式的 CSS:SVG data url,png data url 和一个引用普通的 png 图片的兼容性 CSS 文件。

  • iconizr

一个 PHP 命令行工具,把 SVG 图片转换成 CSS icon,支持图片优化和 SASS 输出。

相关参考

  • David Bushell: 一个前端 SVG Hacking 的更好方法
  • David Bushell: 使用不依赖于分辨率的 SVG
  • MDN on SVG
  • SVG 相关的浏览器支持
  • Peter Gasston: 使用 Fragment Identifiers 更好地实现 SVG Sprites
  • simuari: SVG 栈
  • SVG.js – “ 轻量的第三方库,可以操作 SVG,还可以实现动画 ”
  • Emmet:一种直接从文本编辑器里面生成 SVG data URI 的方式
  • Compass Inline Data Helpers.
  • Adobe: 给 SVG 添加样式
  • Andrew J. Baker: 驯服 SVG
  • 除了 Illustrator 的其他编辑工具: Inkscape, Sketch
  • Krister Kari: 在移动端浏览器中使用 SVG 图片
  • Kyle Foster: 更优的 SVG 工作流
退出移动版