SVG是一种轻量级的矢量图像格式,用于在Web和其他环境上显示各种图形,并支持交互性和动画。在本文中,我们将探讨将CSS与SVG结合使用的各种方法,以及将SVG包含在网页中并对其进行操作的方法。
自1999年以来,可伸缩矢量图形(SVG)格式一直是开放标准,但是自Internet Explorer 9发布以来,浏览器的使用在2011年变得可行。如今,尽管更多高级功能可能有所不同,但所有浏览器都很好地支持SVG。
SVG的好处
位图图像(例如PNG,JPG和GIF)定义了各个像素的颜色。100×100 PNG图像需要10,000像素。每个像素需要四个字节来表示红色,绿色,蓝色和透明性,因此生成的文件为40,000个字节(再加上一些元数据)。应用压缩以减小文件大小;PNG和GIF使用类似ZIP的无损压缩,而JPG有损,并删除不太明显的细节。
位图是照片和更复杂图像的理想选择,但是随着图像放大,清晰度会下降。
SVG是用XML定义的矢量图像。点,线,曲线,路径,椭圆,矩形,文本等在SVG画布上绘制。例如:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600">
<circle cx="400" cy="300" r="250" stroke-width="20" stroke="#f00" fill="#ff0" />
</svg>
所述viewBox
定义的坐标空间。在此示例中,从位置0,0开始的800×600区域具有一个黄色圆圈,并在中心绘制了红色边框:
向量优于位图的优点:
-
上面的SVG使用的字节数少于150个,比同等的PNG或JPG小得多
-
SVG背景默认为透明
-
图像可以缩放到任意大小而不会降低质量
-
SVG代码/元素可以在服务器或浏览器上轻松生成和操纵
-
就可访问性和SEO而言,文本和绘图元素是机器和人类可读的。
SVG非常适合徽标,图表,图标和更简单的图表。尽管SVG已用于延迟加载占位符,但通常仅照片是不切实际的。
SVG工具
这是了解有用的基本的SVG绘图,但你很快就想用,可以生成的代码编辑器创建更复杂的形状。选项包括:
-
Adobe Illustrator(商业)
-
Affinity Designer(商业)
-
Sketch(商业)
-
Inkscape(开源)
-
Gravit Designer(免费,在线)
-
Vectr(免费,在线)
-
SVG-Edit(开源,在线)
-
Boxy SVG(免费,应用程序,在线,但仅Blink浏览器)
-
Vecteezy --(免费,在线,但仅Blink浏览器)
-
SVG图表库 -通常使用传递给JavaScript函数的数据来创建SVG图表。
每个都有不同的优势,对于看似相同的图像,您将获得不同的结果。通常,更复杂的图像需要更复杂的软件。
通常,可以使用SVGO(大多数构建工具都提供插件)来简化和最小化结果代码,或者使用Jake Archibold的SVGOMG交互式工具。
SVG作为静态图像
在HTML <img>
标签或CSS中使用时background-url
,SVG的作用与位图相同:
<!-- HTML image -->
<img src="myimage.svg" alt="a vector graphic" />
/* CSS background */.myelement {
background-image: url('mybackground.svg');}
浏览器将禁用SVG文件中嵌入的所有脚本,链接和其他交互功能。您可以使用CSS来操作SVG,其方式与使用transform
,filters
等的其他图像相同。使用CSS与SVG的结果通常优于位图,因为SVG可以无限缩放。
CSS内联SVG背景
SVG可以直接嵌入CSS代码中作为背景图像。这对于较小的可重复使用的图标非常理想,并且避免了其他HTTP请求。例如:
.mysvgbackground {
background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600"><circle cx="400" cy="300" r="50" stroke-width="5" stroke="#f00" fill="#ff0" /></svg>') center center no-repeat;
}
可以使用标准UTF-8编码(而不是base64),因此如有必要,可以轻松地编辑SVG图像。
带有SVG的CSS:响应式SVG图像
创建响应式网站时,通常通常会省略<img>
width
和height
赋予属性,并通过CSS将图片调整为最大宽度:
img {
display: block;
max-width: 100%;
}
但是,用作图像的SVG没有隐式尺寸。您可能会发现的max-width
计算为零,并且图像完全消失了。要解决此问题,请确保使用默认值,width
并height
在<svg>
标记中进行了定义:
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="300">
注意:尺寸不应添加到内联SVG中,因为我们将在下一部分中发现......
HTML内嵌的SVG图片
SVG可以直接放入HTML中。完成此操作后,它们将成为DOM的一部分,并且可以使用CSS和JavaScript进行操作:
<p>SVG is inlined directly into the HTML:</p>
<svg id="invader" xmlns="http://www.w3.org/2000/svg" viewBox="35.4 35.4 195.8 141.8">
<path d="M70.9 35.4v17.8h17.7V35.4H70.9zm17.7 17.8v17.7H70.9v17.7H53.2V53.2H35.4V124h17.8v17.7h17.7v17.7h17.7v-17.7h88.6v17.7h17.7v-17.7h17.7V124h17.7V53.2h-17.7v35.4h-17.7V70.9h-17.7V53.2h-17.8v17.7H106.3V53.2H88.6zm88.6 0h17.7V35.4h-17.7v17.8zm17.7 106.2v17.8h17.7v-17.8h-17.7zm-124 0H53.2v17.8h17.7v-17.8zm17.7-70.8h17.7v17.7H88.6V88.6zm70.8 0h17.8v17.7h-17.8V88.6z"/>
<path d="M319 35.4v17.8h17.6V35.4H319zm17.6 17.8v17.7H319v17.7h-17.7v17.7h-17.7V159.4h17.7V124h17.7v35.4h17.7v-17.7H425.2v17.7h17.7V124h17.7v35.4h17.7V106.3h-17.7V88.6H443V70.9h-17.7V53.2h-17.7v17.7h-53.2V53.2h-17.7zm88.6 0h17.7V35.4h-17.7v17.8zm0 106.2h-35.5v17.8h35.5v-17.8zm-88.6 0v17.8h35.5v-17.8h-35.5zm0-70.8h17.7v17.7h-17.7V88.6zm70.9 0h17.7v17.7h-17.7V88.6z"/>
</svg>
<p>The SVG is now part of the DOM.</p>
没有width
或height
属性的SVG定义的,所以它可以大小包含元素或使用CSS被直接尺寸,看个DEMO:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
font-family: sans-serif;
}
#invader {
display: block;
width: 200px;
margin: 3em auto;
animation: move 2s ease-in-out 0s infinite alternate;
}
#invader path {
stroke-width: 0;
fill: #080;
animation: flash 1s linear 0s infinite alternate;
}
#invader path:hover {
fill: #c00;
}
@keyframes move {
0% { transform: translate(-200px); }
50% { transform: scale(1.2); }
100% { transform: translateX(200px); }
}
@keyframes flash {
0% { opacity: 1; }
0% { opacity: 0.4; }
}
</style>
</head>
<body>
<p>SVG is inlined directly into the HTML:</p>
<svg id="invader" xmlns="http://www.w3.org/2000/svg" viewBox="35.4 35.4 195.8 141.8">
<path d="M70.9 35.4v17.8h17.7V35.4H70.9zm17.7 17.8v17.7H70.9v17.7H53.2V53.2H35.4V124h17.8v17.7h17.7v17.7h17.7v-17.7h88.6v17.7h17.7v-17.7h17.7V124h17.7V53.2h-17.7v35.4h-17.7V70.9h-17.7V53.2h-17.8v17.7H106.3V53.2H88.6zm88.6 0h17.7V35.4h-17.7v17.8zm17.7 106.2v17.8h17.7v-17.8h-17.7zm-124 0H53.2v17.8h17.7v-17.8zm17.7-70.8h17.7v17.7H88.6V88.6zm70.8 0h17.8v17.7h-17.8V88.6z"/>
<path d="M319 35.4v17.8h17.6V35.4H319zm17.6 17.8v17.7H319v17.7h-17.7v17.7h-17.7V159.4h17.7V124h17.7v35.4h17.7v-17.7H425.2v17.7h17.7V124h17.7v35.4h17.7V106.3h-17.7V88.6H443V70.9h-17.7V53.2h-17.7v17.7h-53.2V53.2h-17.7zm88.6 0h17.7V35.4h-17.7v17.8zm0 106.2h-35.5v17.8h35.5v-17.8zm-88.6 0v17.8h35.5v-17.8h-35.5zm0-70.8h17.7v17.7h-17.7V88.6zm70.9 0h17.7v17.7h-17.7V88.6z"/>
</svg>
<p>The SVG is now part of the DOM and can be manipulated in CSS and JavaScript.</p>
<script>
const
viewX = [35.4, 283.6],
animationDelay = 400,
invader = document.getElementById('invader');
let frame = 0;
setInterval(() => {
frame = ++frame % 2;
invader.viewBox.baseVal.x = viewX[frame];
}, animationDelay);
</script>
</body>
</html>
SVG元素(例如路径,圆形,矩形等)可以被CSS选择器作为目标,并使用标准SVG属性作为CSS属性来修改样式。例如:
/* CSS styling for all SVG circles */
circle {
stroke-width: 20;
stroke: #f00;
fill: #ff0;
}
这会覆盖SVG中定义的所有属性,因为CSS具有更高的特异性。SVG CSS样式具有以下优点:
-
可以从SVG中完全删除基于属性的样式,以减少页面权重
-
CSS样式可以在任意数量的页面上的任意数量的SVG中重复使用
-
全SVG或图像的各个元素可具有CSS效果应用于使用
:hover
,transition
,animation
等。
SVG精灵
单个SVG文件可以包含任意数量的单独图像。例如,此folders.svg
文件包含IcoMoon生成的文件夹图标。每个都包含在一个单独的<symbol>
容器中,该容器具有可以定位的ID:
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="icon-folder" viewBox="0 0 32 32">
<title>folder</title>
<path d="M14 4l4 4h14v22h-32v-26z"></path>
</symbol>
<symbol id="icon-folder-open" viewBox="0 0 32 32">
<title>open</title>
<path d="M26 30l6-16h-26l-6 16zM4 12l-4 18v-26h9l4 4h13v4z"></path>
</symbol>
<symbol id="icon-folder-plus" viewBox="0 0 32 32">
<title>plus</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-4v4h-4v-4h-4v-4h4v-4h4v4h4v4z"></path>
</symbol>
<symbol id="icon-folder-minus" viewBox="0 0 32 32">
<title>minus</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-12v-4h12v4z"></path>
</symbol>
<symbol id="icon-folder-download" viewBox="0 0 32 32">
<title>download</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM16 27l-7-7h5v-8h4v8h5l-7 7z"></path>
</symbol>
<symbol id="icon-folder-upload" viewBox="0 0 32 32">
<title>upload</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM16 15l7 7h-5v8h-4v-8h-5l7-7z"></path>
</symbol>
</defs>
</svg>
可以将SVG文件引用为HTML页面中的外部缓存资源。例如,要显示文件夹图标#icon-folder
:
<svg class="folder" viewBox="0 0 100 100">
<use xlink:href="folders.svg#icon-folder"></use>
</svg>
并使用CSS设置样式:
svg.folder { fill: #f7d674; }
该方法有两个缺点:
-
在IE9 +中失败。
-
CSS样式仅适用于
<svg>
包含的元素<use>
。在fill
这里,使图标的每个元素相同的颜色。
为了解决这些问题,可以将SVG精灵嵌入页面HTML中,然后使用display: none
或类似技术将其隐藏。可以通过引用ID来放置单个图标:
<svg><use xlink:href="#icon-folder"></use></svg>
看个DEMO:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
body {
font-family: sans-serif;
font-size: 100%;
}
.icons {
display: flex;
justify-content: space-between;
margin: 0;
padding: 0;
list-style-type: none;
}
.icons li {
margin: 3px;
}
.icons svg {
display: block;
width: 100%;
fill: #f7d674;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;">
<defs>
<symbol id="icon-folder" viewBox="0 0 32 32">
<title>folder</title>
<path d="M14 4l4 4h14v22h-32v-26z"></path>
</symbol>
<symbol id="icon-folder-open" viewBox="0 0 32 32">
<title>open</title>
<path d="M26 30l6-16h-26l-6 16zM4 12l-4 18v-26h9l4 4h13v4z"></path>
</symbol>
<symbol id="icon-folder-plus" viewBox="0 0 32 32">
<title>add</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-4v4h-4v-4h-4v-4h4v-4h4v4h4v4z"></path>
</symbol>
<symbol id="icon-folder-minus" viewBox="0 0 32 32">
<title>remove</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM22 22h-12v-4h12v4z"></path>
</symbol>
<symbol id="icon-folder-download" viewBox="0 0 32 32">
<title>download</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM16 27l-7-7h5v-8h4v8h5l-7 7z"></path>
</symbol>
<symbol id="icon-folder-upload" viewBox="0 0 32 32">
<title>upload</title>
<path d="M18 8l-4-4h-14v26h32v-22h-14zM16 15l7 7h-5v8h-4v-8h-5l7-7z"></path>
</symbol>
</defs>
</svg>
<h1>Folder icons</h1>
<ul class="icons">
<li><svg><use xlink:href="#icon-folder"></use></svg></li>
<li><svg><use xlink:href="#icon-folder-open"></use></svg></li>
<li><svg><use xlink:href="#icon-folder-plus"></use></svg></li>
<li><svg><use xlink:href="#icon-folder-minus"></use></svg></li>
<li><svg><use xlink:href="#icon-folder-download"></use></svg></li>
<li><svg><use xlink:href="#icon-folder-upload"></use></svg></li>
</ul>
<script>
</script>
</body>
</html>
这适用于IE9 +的所有现代浏览器,并且可以使用CSS在每个图标中设置单个元素的样式。
不幸的是,SVG集不再被缓存,并且必须在需要图标的每个页面上复制。解决方案(针对此解决方案!)是使用Ajax加载SVG(然后将其缓存),然后将其注入页面中。该IcoMoon下载提供了一个JavaScript库。
SVG对HTML内容的影响
SVG长期以来一直支持:
-
masks: 更改元素各部分的可见性
-
clipping: 删除元素的分段,以便标准的常规框变为任何其他形状
-
filters: 图形效果,例如模糊,亮度,阴影等。
这些影响已经被移植到CSS mask
,clip-path
以及filter
性能。但是,仍然可以定位SVG选择器:
/* CSS */
.myelement {
clip-path: url(#clip);
}
这引用了嵌入HTML的SVG中的效果:
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;">
<defs>
<clipPath id="clip">
<text x="0" y="200" font-family="Arial" font-size="10em" font-weight="800">Text Clip</text>
</clipPath>
</defs>
</svg>
产生效果,例如带有图像或渐变背景的剪切文本,来个DEMO看下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.area {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: radial-gradient(circle, rgba(131,58,180,1) 0%, rgba(253,29,29,1) 50%, rgba(252,176,69,1) 100%);
clip-path: url(#clip);
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;">
<defs>
<clipPath id="clip">
<text x="0" y="200" font-family="Arial" font-size="10em" font-weight="800">Web前端之家</text>
</clipPath>
</defs>
</svg>
<div class="area"></div>
<script>
</script>
</body>
</html>
便携式SVG
最后,独立的SVG可以包含CSS,JavaScript和base64编码的字体或位图图像!XML范围以外的任何内容都应包含在<![CDATA[
... ]]>
部分中。
考虑以下invader.svg
文件。它使用悬浮效果和修改viewBox
状态的JavaScript动画定义CSS样式:
<svg id="invader" xmlns="http://www.w3.org/2000/svg" viewBox="35.4 35.4 195.8 141.8">
<!-- invader images: https://github.com/rohieb/space-invaders !-->
<style>/* <![CDATA[ */
path {
stroke-width: 0;
fill: #080;
}
path:hover {
fill: #c00;
}
/* ]]> */</style>
<path d="M70.9 35.4v17.8h17.7V35.4H70.9zm17.7 17.8v17.7H70.9v17.7H53.2V53.2H35.4V124h17.8v17.7h17.7v17.7h17.7v-17.7h88.6v17.7h17.7v-17.7h17.7V124h17.7V53.2h-17.7v35.4h-17.7V70.9h-17.7V53.2h-17.8v17.7H106.3V53.2H88.6zm88.6 0h17.7V35.4h-17.7v17.8zm17.7 106.2v17.8h17.7v-17.8h-17.7zm-124 0H53.2v17.8h17.7v-17.8zm17.7-70.8h17.7v17.7H88.6V88.6zm70.8 0h17.8v17.7h-17.8V88.6z"/>
<path d="M319 35.4v17.8h17.6V35.4H319zm17.6 17.8v17.7H319v17.7h-17.7v17.7h-17.7V159.4h17.7V124h17.7v35.4h17.7v-17.7H425.2v17.7h17.7V124h17.7v35.4h17.7V106.3h-17.7V88.6H443V70.9h-17.7V53.2h-17.7v17.7h-53.2V53.2h-17.7zm88.6 0h17.7V35.4h-17.7v17.8zm0 106.2h-35.5v17.8h35.5v-17.8zm-88.6 0v17.8h35.5v-17.8h-35.5zm0-70.8h17.7v17.7h-17.7V88.6zm70.9 0h17.7v17.7h-17.7V88.6z"/>
<script>/* <![CDATA[ */
const
viewX = [35.4, 283.6],
animationDelay = 500,
invader = document.getElementById('invader');
let frame = 0;
setInterval(() => {
frame = ++frame % 2;
invader.viewBox.baseVal.x = viewX[frame];
}, animationDelay);
/* ]]> */</script>
</svg>
在HTML <img>
或CSS背景中引用时,SVG成为初始状态(本质上是第一个动画帧)的静态图像:
但是,在其自己的浏览器选项卡中打开图像,所有效果都会返回。
这对于分发需要一定程度的嵌入式交互性的图像,演示或小型文档可能很有用。
复杂的SVG
SVG在网页内外都提供了广泛的技术可能性。将CSS与SVG结合使用时,可以以有趣的方式对整个图像或单个元素进行样式设置和动画处理。
本文介绍了处理SVG图像的方法,但是它们通常用于较小的视觉增强,例如:
-
表单重点摘要和验证
-
将汉堡菜单变成
X
关闭图标 -
产生类似熔岩灯的变形。
Web开发人员在探索通过将CSS与SVG结合使用来转换无聊的基于块的页面的方法,从而产生微妙的效果。如果您创建任何有趣的示例,都可以加群分享或者留言。