使用html文档,我们可以根据视口的条件显示,隐藏或重新排列页面的某些部分。例如,如果浏览器窗口宽度为480像素,我们可能会将导航从水平导航切换到垂直可折叠列表。我们可以使用媒体查询和svg文档执行类似的操作。考虑一个徽标,例如下面虚构的hexagon web design&development的徽标。
没有媒体查询,此svg徽标将简单地拉伸或缩小以适合视口或其容器。但是通过媒体查询,我们可以做更多聪明的事情。
让我们区分html文档视口和svg文档视口。当svg内联时,html视口和svg视口是同一个。svg文档的行为与任何其他html元素相同。在另一方面,当一个svg文档被链接为与object或img与svg文档的视口的元件-我们处理。
媒体查询在两种情况下都有效,但是当链接svg文档时,其视口独立于其html文档。在这种情况下,浏览器窗口的大小不会确定svg视口的大小。取而代之的是,视口尺寸由尺寸确定object,iframe或img元件。以下面的(删节)svg文档为例:[^ 4]
<svg version=1.1 id=hexagonlogo xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink x=0px y=0px viewbox=0 0 555 174 xml:space=preserve>
<defs>
<style type=text/css>
/* css goes here */
</style>
</defs>
<g id=hex>
<polygon id=hexagonbg points=55.2,162 10,86.5 55.2,11 145.5,11 190.7,86.5 145.5,162 />
<path id=letterh fill=#ffffff d=m58,35.5h33v35.2h18.4v35.5 h33.2v103.4h-33.2v-38.3h91v38.3h58v35.5z m77.5,126.5v87.3h45.6v39.2h4v47.9h-4v35.6h77.5v47.9h-4v78.6h77.5z/>
</g>
<g id=word-mark>
<g id=hexagon-word>
...
</g>
<g id=web-design-and-dev>
...
</g>
</g>
</svg>
在较小的视口中,让我们只显示六边形符号中的h:
@media (max-width: 20em) {
[id=word-mark] {
display: none;
}
}
在较小的视口中,让我们只显示六边形符号中的h:
现在,只要我们的svg容器小于或等于20em,只有我们徽标的符号部分可见,如下所示。
要从html文档触发此视图,请设置svg容器的宽度:
<object data=hexlogo.svg type=image/svg+xml style=width: 20em;></object>
正如您从上面的图像中看到的那样,我们的svg图像保留了其内在尺寸,即使其中一部分已被隐藏。不幸的是,这是svg的限制。要修复它,我们需要更改viewboxsvg文档的属性,但仅限于视口低于特定大小时。这是一个很好的用例matchmedia。
viewbox顾名思义,该属性决定了svg元素的可视区域。通过调整它,我们可以确定svg图像的哪个部分填充视口。以下是使用matchmedia和媒体查询更新viewbox属性的示例:
<script type=text/javascript>
var svg, originalviewbox, max20em, mq, updateviewbox;
svg = document.queryselector('svg');
/* store the original value in a variable */
originalviewbox = svg.getattribute('viewbox');
/* define our media query and media query object */
mq = matchmedia((max-width: 20em));
/* define the handler */
updateviewbox = function(){
if (mq.matches) {
/* change the viewbox dimensions to show the hexagon */
svg.setattribute('viewbox', 0 0 200 174);
} else {
svg.setattribute('viewbox', originalviewbox);
}
}
/* fire on document load */
// webkit/blink browsers
svg.onload = updateviewbox;
// firefox & ie
svg.addeventlistener('svgload', updateviewbox, true);
/* fire if the media condition changes */
mq.addlistener(updateviewbox);
</script>
注意:在处理svgload事件时,浏览器有点乱。在我的测试中,addeventlistener与firefox一致。要在chrome和safari中获得最佳效果,请使用onloadevent属性。microsoft edge也最适用onload,但仅在用作<svg>标记的属性时才有效。换句话说,。<svg onload=updateviewbox>
现在,每当svg容器为20em或更小时,其值viewbox将为0 0 200 174。当它超过时20em,viewbox将恢复到其初始值,如下所示。
注意:有关创建交互式svg文档的更全面的入门读物,请阅读?w3c的今日浏览器的svg primer?的“?动态svg和javascript?”一章。
由于此技术使用onload事件属性或svgload事件,因此将css和javascript嵌入svg文件中是个好主意。当css是外部的时,svgload事件可能在其关联的css完成加载之前触发。
使用媒体查询?background-sizesvg文档和媒体查询不限于前景图像。我们还可以使用css?background-size属性调整svg视口的大小。所有最新的主流浏览器都支持这种技术,但较旧的浏览器版本则不支持。在生产中使用此技术时要小心。
我们将从这个svg文档开始:
<?xml version=1.0 encoding=utf-8?>
<svg version=1.1 id=layer_1 xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink x=0px y=0px viewbox=-20 -20 250 250 xml:space=preserve>
<style type=text/css>
circle {
stroke: #000;
stroke-width: 30;
fill: #009688;
}
@media (width: 100px) {
circle {
fill: #673ab7;
}
}
@media (width: 300px) {
circle {
fill: #ffc107;
}
}
</style>
</defs>
<circle cx=100 cy=100 r=100 />
<circle cx=100 cy=100 r=50 />
</svg>
这是一个简单的案例。我们的circle元素将fill在特定视口宽度处获得新颜色。当视口宽度为20像素时,填充将为蓝绿色。当它宽300像素时,它将是黄色。
为了使这项工作,我们必