• 售前

  • 售后

热门帖子
入门百科

深入剖析HTML5使用SVG图像时的viewBox属性用法

[复制链接]
小菊花之米 显示全部楼层 发表于 2021-10-26 12:51:38 |阅读模式 打印 上一主题 下一主题
快速了解viewBox的参数
viewBox属性是用于指定用户SVG图像的坐标系统的原点以及尺寸的。所有在SVG内绘制的内容都是相对于这个坐标系统完成的。由于SVG画布在所有方向都是无限延长的,你乃至可以在这个坐标系统的边界之外的地方绘制图形;但是这些相对于SVG视窗定位的图形,也可以由用户坐标系的位置来控制。
viewBox属性使用四个参数来指定坐标系原点的位置以及它的尺寸:x y width height。初始情况下,这个坐标系等同于初始化的视窗坐标系(由SVG图像的width和height确定),而且它的原点是在(0, 0)——即SVG的左上角。
通过改变x和y这两个参数的值,可以调整原点的位置。改变width和height的值,可以改变坐标系统的尺寸。只使用viewBox属性,就可以帮你扩展或裁剪SVG画布。跟着示例一起阅读。
告急提示:在本文章中,我不会改变viewBox在SVG视窗内的默认行为(比例和位置)。由于,根据属性的默认行为,viewBox的内容会被尽大概地完全包罗在视窗内,然后放置在中央位置。不外,使用preserveAspectratio属性可以让你自由地改变viewBox的尺寸和位置,但是在这篇文章中,这不是必需的技术,以是我们也不会在这里深入讲授。
使用viewBox裁剪SVG,即使用viewBox属性制作Art Direction的SVG
前阵子,我的一个客户要求把他网站的SVG头像按照不同的屏幕尺寸设置成不同的巨细,从而使得它只有一小部分是在小屏幕上可见的,在中等的屏幕尺寸上可以看到再大一点的部分,然后在大屏幕上可以看到完备的内容。其时我头脑里起首出现的想法就是,他的要求实在是使用viewBox属性来裁剪SVG图像,然后根据不同的屏幕尺寸,表现他想要看到的图像的某部分。
通过改变SVG坐标系统的尺寸和原点位置,我们可以把SVG举行裁剪,并表现我们希望在视窗中表现的那部分内容。
我们来看看怎样实现。
假设我们有如下这张完备的SVG图像,然后我们想要把它裁剪成小屏幕的尺寸。这张图是Freepik计划的可免费使用的房屋矢量图,该图片有Creative Commons Attribution 3.0 Unported协议的答应授权。为了简朴起见,我们先假设图像只是要被裁剪成在中小屏幕上表现的内容,以及大屏幕上表现的完备的内容,如下所示。

左边的图的是我们将要使用viewBox属性裁剪的完备的图片,右边的图是我们希望在小屏幕上表现的区域。
如今,通过改变viewBox属性的值来裁剪SVG。有一些需要思量的内容,我们等下会讲到。但是起首,我们要改变坐标系统,让它匹配上面的图片中虚框矩形区域的内容。,通过调整系统的原点以及width和height的值,我们可以改变它初始的0 0 800 800参数值。
但是我们要怎样获知新坐标和新尺寸呢?重点是不要经过大量重复的实行和错误。
有几种方式。由于我们已经在图形编辑器中(我的示例使用的是AI),我们可以使用编辑器的面板来获取元素的位置和尺寸。
我画这个虚线的矩形框,除了用来表现我想要在小屏幕上表现的内容,还有一个原因就是:我们可以获取这个矩形的位置和尺寸,然后把它们作为viewBox的值来使用。使用AI的变换面板(如下图),我们获取了我们需要的这些值。通过选择矩形,并点击右上角的变换链接,我们得到了如下图所示的面板,包括我们所需要的x, y, width和height值。

这个AI中的变换面板可以用来获取选中矩形的位置和尺寸的值
你大概注意到了,上面的值并不是整数,以是我们需要手动修改。根据上面的信息,我们把viewBox的值改成 0 200 512 512。
由于新的viewBox的宽高比和SVG视窗的宽高比是一样的(都是正方形),viewBox内的内容将会扩大,而且只有被选中的区域会在视窗中表现。改变viewBox的值之后,结果如图:

新裁剪的SVG。只有我们指定使用viewBox属性的位置在视窗中是可见的。蓝色边框表现SVG的视窗。
在这一点上,有一个问题需要办理:
假如被裁剪区域(即viewBox)的宽高比 != SVG视窗的宽高比?
在这种情况下,将会有显着的溢出。显着的溢出,我指的不是超出SVG视窗边界的延伸,而是viewBox界说的相对于新用户坐标系统的溢出。下图作了相应的阐明。


假如viewBox的宽高比和视窗的宽高比不同,SVG中的内容会溢出用户坐标系统,结果大概会是这样。
玄色边框代表新的用户坐标系,蓝色边框是SVG视窗。
上边右图中的玄色边框是viewBox界说的区域。根据viewBox在视窗内的默认行为,它会被居中并尽大概放大,来包管自身内容尽大概地包罗在视窗(蓝色边框)中。
由于SVG画布从概念上来说,在所有方向都是无限延伸的,你可以在用户坐标系统边界之外绘制图形,内容会直接溢出移动,如上图所示。
假如你改变了SVG视窗的宽高比(SVG的width和height),来让它们适应viewBox的宽高比,你就不会看到溢出了,由于viewBox的缩放是适应视窗的,和前面的示例一样。
但是,在某些情况下,你大概不能或根本不想改变SVG的宽高比。好比说,假如你是使用SVG sprite作为一组图像来表现页面上图片的。在大多数情况下,图像都有一个固定的宽高比——而且你并不想改变改变图像的尺寸,就为了适应它内里的某一张小图的内容。或者大概你嵌入了一个图标系统,并希望所有的图标在同一个时间都保持雷同的尺寸。
为了剪掉多余的东西(好比说,sprite上的部分别的图标,在视窗中表现),你可以使用<clipPath>来把多余的部分裁剪掉。裁剪路径可以是一个覆盖了整个viewBox区域的<rect>元素,然后将该元素应用到root SVG。
但是,还有一点要记住:确保<rect>的x和y属性和viewBox的保持同等,除非rect将被相对定位于原来的/初始化的系统的原点,那么SVG终极被裁剪的内容也是不确定的。
CSS Code复制内容到剪贴板
       
  • <svg xmlns="http://w3.org/2000/svg" viewBox="vx vy width height" clip-path="url(#clipper)" width=".." height="..">      
  •     <!-- SVG content here -->      
  •     <clipPath id="clipper">      
  •         <rect x="vx" y="vy" width="100%" height="100%"></rect>      
  •     </clipPath>      
  • </svg>  
当然,裁剪多余的部分也就意味着你仍旧在使用不同的宽高比,还是需要办理内容双方多出的空缺。假如SVG是一个一连的场景,像我们前面的谁人例子,那就没须要了,由于你还需要调整视窗的宽高比。假如SVG是一组图标,而且你只是在不同的视窗中使用一次,这大概就不是问题了。
这里有一点告急的东西要记住,viewBox的宽高比最好还是和视窗的宽高比保持同等;别的,你需要设置固定来克制SVG中任何不确定的多余的空缺出现。
以是,viewBox可以用来裁剪SVG,并根据需要只展示SVG的某部分内容。但是它要怎样应用于实例呢?
在响应式计划中的Art Directing SVG
这部分没有什么需要补充的内容,除了实际过程的代码。以是,假设你有如上所示的SVG,而且想要把它作为头像,好比说,在中小尺寸的屏幕上你只想表现裁剪下来的那部分内容,然后在大屏幕上表现完备的头像。
改变SVG视窗的width和height值,我们可以使用CSS。但是改变viewBox的值,如今我们需要使用JavaScript。
并非所有的SVG属性,CSS属性都可以等同使用;只有一组具有和CSS属性雷同结果的属性才可以在CSS中设置。你可以在这个表格中检察这组可以作为CSS属性的SVG属性的概述。在SVG2中,许多属性(如x, y, cx, cy, r等等)都可以被添加到这个列表中;但是这些都是我们如今可以使用的属性。
为了展示SVG的不同部分,需要基于不同媒体查询改变viewBox的值,你可以使用Modernizr,查找媒体查询条件,然后在JavaScript中对应更改viewBox的值。示比方下:
CSS Code复制内容到剪贴板
       
  • // 获取root <svg>的引用      
  • var svgRoot = ...; // 取决于你怎样嵌入并引用SVG      
  • // 界说viewBox的参数值      
  • var vbValue = '0 200 512 512';      
  • // 使用Modernizr的媒体查询检索来改变viewBox的值      
  • if (Modernizr.mq('(max-width: 700px)')) {      
  •    svgRoot.setAttribute('viewBox', vbValue);      
  • }      
  • // 别的的尺寸情况  
这是可以运行的,但是假如我们可以使用CSS来完成这个结果岂不更赞?
使用CSS的viewBox属性来裁剪SVG
免责声明:在写这篇文章的时候,并没有CSSviewBox属性。这只是一个用来表明为什么这个属性有用,以及我想象的它怎样被使用的示例。
理想情况下,我们可以这样使用它:
CSS Code复制内容到剪贴板
       
  • <style>      
  •       
  • @media screen and (max-width: 700px) {      
  •     svg {              
  •         viewBox: 0 200 512 512;        
  •     }        
  • }      
  •       
  • /* etc. */      
  •       
  • </style>  
这些样式会被放进(或取出)SVG中,然后SVG将会根据视窗的尺寸调整其viewBox值。让它成为页面视窗(内联<svg>)的情况),或是通过别的任何引用SVG的元素的尺寸确定的视窗(这可以给我们一些近乎雷同的元素查询)。
不外,这在如今是不大概实现的,由于CSS中还没有viewBox属性。
前阵子,我就这个问题扣问了一个SVG规范的编辑,他说我可以根据实际使用情况和实例,向SVGWG提发起。后来在Twitter上举行了一些讨论,我才发如今几年前已经有一个相似的SVGWG proposal thread。当初的提议今天仍旧存在,以是我希望,能够通过一些实际使用示例,推进这个提议,并在不久的将来可以实现。假如你也想要在CSS中看到viewBox属性,请帮助实现这一目的,推动这个提议的转发和批评。
当使用viewBox完成SVG Art-Direction的时候,需要记住的东西
在做我的客户的项目的时候,我花了一分钟不到的时间来按照对方的要求对头像举行art-direct。但是,这终极分出了三个独立的SVG,而不是不同屏幕尺寸上的雷同SVG不同viewBox。
我们选择三个SVG的原因是,完备SVG的尺寸太大,在移动端到达了100kb以上的巨细。最初的SVG是200kb左右的,我可以通过优化SVG来把文件压缩到接近一半的巨细,但是对于移动装备来说,图片还是太大了,以是末了我们只能使用三张不同巨细的图像。art-directing SVG的时候,需要记住的就是:性能问题。假如你的SVG太大了,不要使用viewBox来art-direct。
如今,假如你选择使用三个不同的SVG图像,也有多种大概的方式可以完成——这取决于你嵌入SVG的方法,也取决于你想要完成什么、不想完成什么。
使用<picture>元素来完成不同SVG图像是最理想的方式。它不但能够根据欣赏器为我们提供不同的可供选择的SVG,而且还不需要使用JavaScript,还可以让我们对不支持它的欣赏器(IE8及以下)提供多种优化的降级图像。<picture>对于使用SVG是非常有用的,你可以在这篇文章中阅读所有SVG fallback的内容。
但是如前面所说,假如你想要有动画或交互结果的SVG,<picture>不是最佳选择。就像使用<img>嵌入SVG,SVG不能被添加样式和动画,除非样式和动画是在<svg>文件中界说的,SVG不能添加脚本(出于安全思量),也不能有任何交互(CSS或JS)——好比说,悬停,不会有交互结果。
以是,我总是说:SVG为我们提供了许多选项,可以让我们完成几乎所有的事情;你需要做一个衡量、要主次分明、偶尔乃至需要作出妥协,基于此作出最佳的选择。但是对于性能,永不妥协才有利于发展!
在我们结束之前,由于我们提到了使用viewBox属性改变SVG画布尺寸的问题,我们来看看另一个例子,我们可以借助这个属性来帮我们在处理SVG时节省一些时间和精神。
使用viewBox扩展SVG画布
正如viewBox属性可以用于缩放SVG,它也可以用来扩展SVG画布。
几周前我创建了一个可以天生SVG圆形菜单的工具。我创建了几个例子来演示怎样使用JavaScript让天生的菜单动起来。demo使用<object>元素嵌入到应用程序页面上。<object>的边界界说了SVG视窗的边界,任安在这些边界之外的内容都是溢出,而且默认隐蔽。
需要注意的是“边界之外”指的是在SVG中的内容,它还是在无穷大的SVG画布上的,但是超过了由视窗界说的无穷大的矩形
译者注:关于SVG画布、视窗的内容可阅读w3cplus上的相关文章。
创建的菜单,SVG的尺寸是恰好可以将菜单包罗进去,而没有再大一些。克制了菜单周围任何多余的空缺。
我给某个菜单应用了一个弹跳动画,作为菜单动画的示例。这个弹跳结果“拉长了”各菜单项,也导致了菜单项在它们弹跳的时候会单独切出来(即溢出)。

早先,由于SVG视窗是由<object>元素界说的,以是视窗和菜单本身是一样大的,菜单项上的弹跳结果导致了这些菜单项在弹跳的时候溢出。
这些可爱的弹跳动画应用于那些使用弹跳时间函数从0开始放大到100%的项目(即该项目最初是不可见的,缩小状态),这个结果就是假如项目弹跳到超过了100%的巨细,那就把它缩回到100%。这个结果会导致项目在弹跳超过SVG边界的时候溢出。
下图展示了缩放菜单项在放大到超过<object>的边界(灰色边框)的时候的结果,此中,<object>用于嵌入这个缩放菜单项。

上方的表示图展示了菜单项放大到溢出SVG视窗边界时的结果。灰色边框表现SVG视窗的边框(即<object>元素)。
给<object>设置overflow: visible也不能办理问题,由于<object>和<iframe>实际上是相似的。我们需要做的是扩展<object>创建的视窗内的SVG画布,使得缩放的项目有充足的“反弹”空间,而不会超过它的边界。我们可以使用viewBox属性来完成它。
为了延长SVG画布,只需简朴增加它的尺寸。因此,我们使用的是700 x 500px的尺寸,而不是500 x 250这个SVG菜单的原始尺寸。这还会让画布在视窗中表现的高度增加100px,而视窗中的画布宽度会增加200px。我根据这些菜单项在弹跳结果需要放大的空间来确定这些值。根据您的SVG以及您要完成的详细内容,这些值并不要求同等。
如今,为了确保菜单是放置在视窗的中央的,我们需要把坐标系统的位置往负方向分别移动100px(即向上和向左)。把这个移动应用到坐标系统的原点上,和把一个平移转换应用到系统中的菜单上是一样的。结果是菜单会在视窗中保持居中。

在该图中,蓝色边框表现SVG视窗边界(即<object>元素),灰色边框表现用户坐标系统的初始尺寸。蓝色数字和箭头表现视窗中的坐标系统的扩展。
在延长用户坐标系统尺寸的同时,你也增加了画布在视窗中可见区域的面积。这样做的结果是画布的内容会显得略小——这根据你把画布放大了多少而定。但是对于菜单来说,这样的结果是可以担当的。
下面的屏幕纪录表现了扩展SVG画布的结果,以及在SVG边界内的菜单动画结果。

一旦SVG画布被扩展,菜单项就有充足的空间来举行缩放,在应用弹跳结果的时候也不会再由于溢出被剪切。
通过改变viewBox属性的四个参数值来延伸SVG画布,这样所有问题以及菜单项被剪切的问题都可以办理。viewBox确实非常棒~~
结束语
viewBox属性非常棒,它就是一个SVG的增强版工具。通过使用这个属性,在使用SVG举行工作时就可以节省许多时间,无需借助图形编辑器即可快速办理SVG的问题。总而言之,这对于编辑SVG真的方便了许多。
我强烈发起你全面学习一下这个属性,然后让它在你的工作中发光发热。假如你想要使用它来做art-direct SVG,不要忘了性能才是重点。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作