使用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的限制。要修复它,我们需要更改viewBox
SVG文档的属性,但仅限于视口低于特定大小时。这是一个很好的用例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中获得最佳效果,请使用onload
event属性。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-size
SVG文档和媒体查询不限于前景图像。我们还可以使用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像素时,它将是黄色。
为了使这项工作,我们必须使用我们的SVG图像作为背景图像并设置选择器的background-size
属性。在这种情况下,我们将使用我们的图像作为身体element
和li
元素的背景。下图显示了结果:
body, li {
background: url(../images/circles.svg);
}
body {
background-color: #9c27b0;
background-size: 300px auto;
}
li {
background-size: 20px auto;
background-repeat: no-repeat;
background-position: left 3px;
padding-left: 25px;
}