lightningminers / article

⚡️闪电矿工翻译组-前端(front end developer)
GNU Lesser General Public License v3.0
58 stars 9 forks source link

Using SVG #43

Open chenmf6 opened 5 years ago

chenmf6 commented 5 years ago

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

原文作者: Chris Coyier

翻译作者: chenmf

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

为什么用SVG

怎么生成SVG

可以在Adobe Illustrator里设计并且得到SVG。下面是一个站在椭圆上的奇异鸟: image 留意到画板刚好贴着设计主体的边缘,画布的大小在SVG里面的重要性和在PNG和JPG里面是一样的。 然后可以直接在Adobe Illustrator里面保存成SVG文件。 image

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

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

<img>标签里面使用SVG

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

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

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

前往codepen查看 image

浏览器支持

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

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

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

2. David Bushell提供了一个更简单的操作:

HTML

3. 使用[SVGeezy](http://benhowdle.im/svgeezy/)

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

HTML

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也需要看[浏览器支持](http://caniuse.com/#feat=svg-css),基本上跟在`<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); }

2. 另一个更方便的方法,就是利用多个背景(`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

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

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

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 优化](http://petercollingridge.appspot.com/svg-optimiser),把需要优化的SVG上传,然后下载新的就可以了。
如果你是硬核玩家,可以直接用这个[NodeJS工具](http://petercollingridge.appspot.com/svg-optimiser)自己优化。

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

SVG

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

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

CSS

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

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

SVG

<svg ...> ...

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

CSS

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

下面是一个完整的例子:

[前往codepen查看](https://codepen.io/chriscoyier/pen/evcBu)
![image](https://user-images.githubusercontent.com/13809734/59545995-b0a55f80-8f59-11e9-9d8c-ff47a44a2296.png)

更多阅读:
- [SVG滤镜的更多应用](https://developer.mozilla.org/en-US/docs/Applying_SVG_effects_to_HTML_content)
- [SVG CSS属性大全](http://www.opera.com/docs/specs/presto25/svg/cssproperties/)(针对Opera)
- [SVG滤镜效果演示](http://ie.microsoft.com/testdrive/graphics/hands-on-css3/hands-on_svg-filter-effects.htm)(由Microsoft提供)

#### 浏览器支持
内联SVG的浏览器支持看[这里](http://caniuse.com/#feat=svg-html5),基本和前面的一样。兼容的方法:

HTML

...

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

同样可以使用Modernizr来兼容:

CSS

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

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

SVG

<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在线转换器](Mobilefish.com),可以转成base64编码,但是这种方式不太推荐。记得去掉换行:
![image](https://css-tricks.com/wp-content/uploads/2013/03/base64-data.png)
它可以在上述的所有场景里面使用,除了内联SVG。

个人比较推荐这个[在线转换器](https://yoksel.github.io/url-encoder/),因为转换之后可读性比较强。

- 用在`<img>`里面

HTML

- CSS里面

CSS

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

- `<object>`里面

HTML

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

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

HTML

data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL...

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

data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://...'

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



#### 自动化工具
- [grunticon](https://github.com/filamentgroup/grunticon)
> 从CSS的角度来看比较易用,为每个icon生成一个class,不用CSS sprites。grunticon输入一个SVG/PNG文件的目录,然后输出对应的3种格式的CSS:SVG data url,png data url和一个引用普通的png图片的兼容性CSS文件。

- [iconizr](https://github.com/jkphl/iconizr)
> 一个PHP命令行工具,把SVG图片转换成CSS icon,支持图片优化和SASS输出。

### 相关参考
- David Bushell: [一个前端SVG Hacking的更好方法](http://dbushell.com/2013/02/04/a-primer-to-front-end-svg-hacking/)
- David Bushell: [使用不依赖于分辨率的SVG](http://coding.smashingmagazine.com/2012/01/16/resolution-independence-with-svg/)
- [MDN on SVG](https://developer.mozilla.org/en-US/docs/SVG)
- SVG相关的[浏览器支持](http://caniuse.com/#search=svg)
- Peter Gasston: [使用Fragment Identifiers更好地实现SVG Sprites](http://www.broken-links.com/2012/08/14/better-svg-sprites-with-fragment-identifiers/)
- simuari: [SVG栈](http://blogs.adobe.com/webplatform/2013/01/08/svg-styling/)
- [SVG.js](https://svgdotjs.github.io/) - "轻量的第三方库,可以操作SVG,还可以实现动画"
- Emmet:[一种直接从文本编辑器里面生成SVG data URI的方式](http://docs.emmet.io/actions/base64/)
- [Compass Inline Data Helpers](http://compass-style.org/reference/compass/helpers/inline-data/).
- Adobe: [给SVG添加样式](http://blogs.adobe.com/webplatform/2013/01/08/svg-styling/)
- Andrew J. Baker: [驯服SVG](http://buildnewgames.com/taming-the-svg-beast/)
- 除了Illustrator的其他编辑工具: [Inkscape](http://inkscape.org/), [Sketch](http://www.bohemiancoding.com/sketch/#4)
- Krister Kari: [在移动端浏览器中使用SVG图片](http://kristerkari.github.com/adventures-in-webkit-land/blog/2013/03/08/dealing-with-svg-images-in-mobile-browsers/)
- Kyle Foster: [更优的SVG工作流](http://www.youtube.com/watch?v=iVzW3XuOm7E&feature=youtu.be)