Skip to content

Using SVG #43

@chenmf6

Description

@chenmf6

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

原文作者: Chris Coyier

翻译作者: chenmf

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

为什么用SVG

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

怎么生成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");
}
  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查看
image

更多阅读:

浏览器支持

内联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编码,但是这种方式不太推荐。记得去掉换行:
image
它可以在上述的所有场景里面使用,除了内联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//...

自动化工具

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

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

相关参考

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions