原文地址: 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>
标签并且改变 width
和height
来改变它的尺寸,就像 PNG 和 JPG 一样,比如:
前往 codepen 查看
浏览器支持
在 <img>
标签里面使用需要有浏览器支持。基本上在 IE8 以上和 Android 2.3 以上都可以用。
如果你想要在不支持的浏览器里面使用,可以这样:
- 使用 Modernizr 来替换
<img>
的src
属性:
jQuery
if (!Modernizr.svg) {$(".logo img").attr("src", "images/logo.png");
}
- David Bushell 提供了一个更简单的操作:
HTML
<img src="image.svg" onerror="this.onerror=null; this.src='image.png'">
- 使用 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>
中使用是一样的。
如果要在不支持的浏览器里面使用:
- 用 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);
}
- 另一个更方便的方法,就是利用多个背景(
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 工作流