【转】CSS和SVG中的剪切——clip-path属性和<clipPath>元素
2016-05-17 13:37
751 查看
本文由大漠根据SaraSoueidan的《Clipping in CSS and SVG – The clip-path Property and <clipPath> Element》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明原作者相关信息http://sarasoueidan.com/blog/css-svg-clipping/。
——作者:SaraSoueidan
——译者:大漠
CSS和SVG有很多共同之处。CSS有很多特性都是从SVG中引入过来的。其中就有“剪切”的特性。CSS和SVG都允许我们对一个元素进行非矩形的剪切。在这篇文章中,将介绍CSS和SVG中的剪切技术。
特别声明:本文提供的DEMO可能在你的浏览器中不能正常的演示,你应该查看这个表格了解更多相关的信息。你在阅读这篇文章之时没有必要查看提供的DEMO。不是所有的剪切特性都可以实现或者说只能实现部分剪切特性。本文的最大目的是告诉你CSS和SVG中的剪切是如何工作?仅用来做为参考。在文章中的代码不带有任何浏览器的私有前缀,但在示例中还是带了浏览器的私有前缀。
剪切是什么
剪切是一个图形化操作,你可以部分或者完全隐藏一个元素。被剪切的元素可以是一个容器也可以是一个图像元素。元素的哪些部分显示或隐藏是由剪切的路径来决定的。剪切路径定义了一个区域,在这个区域内的内容将会显示,而不在这个区域内的内容不会显示。这个区域被称之为“裁剪区域”。只要在这个区域之外的任何元素都不会显示。包括元素的内容、背景、边框、文本、轮廓等,甚至还包括他的子元素。
剪切的元素可以是任何容器和图片元素。
剪切路径的概念就相当于在元素上定义了一个视窗。它决定了元素哪些部分在这个“视窗”中显示,哪些部分不在这个“视窗”中显示。但他不会影响自身文档流和其他文档流,因为他通常还是以一个矩形区域显示在其他文档流前面,哪怕是剪切出来的区域是不规则的矩形。如果你想改变周围内容元素围绕剪切出来的图形,那就需要使用CSS的图形属性。如果你对这方面知识感兴趣,可以阅读我早前写的相关文章。
CSS中的剪切——clip-path
属性
clip-path属性是CSS Masking模块的一部分。自从2000年以来,剪切都只是SVG中的一部分,现在将这个功能引入到CSS的Msking模块中,所以现在可以对HTML元素和SVG元素进行剪切。
clip-path属性是指定一个应用到元素上的剪切路径。应用在SVG中
<clipPath>元素上的属性值可以完全运用在
clip-path的属性上。你还可以使用CSS Shapes模块中的基本形状来定义剪切路径。这些形状你可以使用形状函数来创建。这些形状态函数包括
polygon()、
circle()、
inset()(用来定义嵌入的矩形)和
ellipse()。
使用
clip-path属性将一个剪切路径运用在一个元素上非常的简单:
/* SVG中的clipPath的使用 */ .element { clip-path: url(#svgClipPathID); } /* 使用CSS中的基本图形函数 */ .element { clip-path: polygon(...); /* 或者其他的图形函数 */ }
例如,我们使用
polygon()函数定义一个多边形的剪切路径,并且把这个路径应用到一个图像上,代码看起来像这样:
img { clip-path: polygon(626px 463px,765px 236px,687px 31px,271px 100px,70px 10px,49px 250px,133px 406px,374px 462px,529px 393px); }
应用上面的代码之后,图像显示成这样:
查看DEMO
基本图形函数允许我们创建一定数量的图形,其中最复杂的就是多边形。如果你想创建一个更为复杂的图形,而且图形看起来不是用直线画出来的,这个时候你就需要使用SVG的
<clipPath>元素。正如
<clipPath>元素名称所暗示的一样,你可以使用这个元素绘制任意路径的图形。这也意味着,你可以使用
<clipPath>元素绘制出任意图形来做为一个剪切路径。
在我们第二个示例中,使用SVG的
clipPath定义一个路径,这个剪切路径看起来像这样:
<svg height="0" width="0"> <defs> <clipPath id="svgPath"> <path fill="#FFFFFF" stroke="#000000" stroke-width="1.5794" stroke-miterlimit="10" d="M215,100.3c97.8-32.6,90.5-71.9,336-77.6 c92.4-2.1,98.1,81.6,121.8,116.4c101.7,149.9,53.5,155.9,14.7,178c-96.4,54.9,5.4,269-257,115.1c-57-33.5-203,46.3-263.7,20.1 c-33.5-14.5-132.5-45.5-95-111.1C125.9,246.6,98.6,139.1,215,100.3z"/> </clipPath> </defs> </svg>
这剪切路径看起来就像一个黑色的描边圈了一个不规则的图形,这是一个简单的剪切路径,不带有任何的填充。
在下一部分中,我们将着重讨论SVG的
<clipPath>元素。但现在,我们来看看如何将定义好的路径运用到图片上:
img { clip-path: url(#svgPath); }
最终效果如下所示:
查看DEMO
事实上,
<clipPath>元素包括很多个基本图形(
<rect>,
<circle>等),
<path>元素,甚至是
<text>元素。
如果在
<clipPath>里面通过
<text>指定文本,那么这个文本就会当成是一个剪切路径,不管文是否可见,文本外的区域都将被剪切掉。
注意,你可以使用任何文本做为剪切路径。这为实现很多效果开启了一扇大门。你可以使用动画图片(比如,gif),甚至是视频,然后选择你需要的文本进行剪切。这里是没有任何限制的。
下面的示例,就是使用文本做为剪切路径:
<svg height="0" width="0"> <defs> <clipPath id="svgTextPath"> <text x="0" y="300" textLength="800px" lengthAdjust="spacing" font-family="Vollkorn" font-size="230px" font-weight="700" font-style="italic"> Blossom </text> </clipPath> </defs> </svg>
SVG中的
<text>最酷的特点就是可以使用自定义字体,就像HTML文本。在我们的示例中使用了Google Web Fonts中的Vollkorn字体。使用
textLength属性,将文本的宽度设置的和图片宽度一样, 并且通过
x和
y来定位文本。注意,
x和
y坐标确认了文本左下角的位置(也就是文本的基线baseline)。
使用上面的文本路径剪切图来的图片效果如下:
查看DEMO
正如我们前面提到的,你还可以在
<clipPath>中使用多个图形形状。在下一节中,将会深入介绍
<clipPath>,这里我们先简单的了解。在这个示例中,我们使用了多个
<circle>形状,他们大小不同,位置不同。
<svg height="0" width="0"> <defs> <clipPath id="svgPath"> <circle stroke="#000000" stroke-miterlimit="10" cx="50" cy="50" r="40" /> <circle stroke="#000000" stroke-miterlimit="10" cx="193.949" cy="235" r="74.576"/> <circle stroke="#000000" stroke-miterlimit="10" cx="426.576" cy="108.305" r="47.034"/> <circle stroke="#000000" stroke-miterlimit="10" cx="346.915" cy="255.763" r="43.644"/> <circle stroke="#000000" stroke-miterlimit="10" cx="255.39" cy="82.882" r="35.17"/> <!-- more circles... --> </clipPath> </defs> </svg>
此时,图像只会在圆中显示,圆外就不会显示:
查看DEMO
正如我们这篇文章中介绍的,你可以使用
clip-path属性应用在SVG元素绘制的路径。在上面演示的示例,剪切路径都是应用在HTML中的
<img>元素上。在接下来的示例中,将演示的是一个剪切路径用于
<svg>的根元素。同样是樱花图片,使用下面SVG的中的
<image>来引用。
SVG中的
<image>元素用来引用一个完整的SVG或像素图像。如果你在
<image>中引用的SVG图像,设置的
width和
height属性,将会用来设置SVG视窗的大小。如果你引用的是像素图像(我们这里的例子就是这样做的),图像将会自动缩放到指定的
width和
height。所以我们要确认好他们的长宽比例,避免图像扭曲。
当你创建一个SVG时,你可以在
<svg>元素上指定其宽度和高度的大小,用于创建一个窗口。任何超过这个窗口的内容都将不会显示出来。你可以通过
<clipPath>元素定制一个窗口。
<svg height="500" width="800"> <image xlink:href="flowers.jpg" x="0" y="0" width="800" height="500"/> <defs> <clipPath id="theSVGPath"> <rect x="0" y="0" stroke="#000000" stroke-miterlimit="10" width="108" height="500"/> <rect x="121.5" y="25.5" stroke="#000000" stroke-miterlimit="10" width="55" height="455"/> <rect x="192.5" y="9.5" stroke="#000000" stroke-miterlimit="10" width="60" height="484"/> <rect x="271.5" y="44.5" stroke="#000000" stroke-miterlimit="10" width="63" height="416"/> <rect x="349.5" y="25.5" stroke="#000000" stroke-miterlimit="10" width="208" height="447"/> <rect x="574.5" y="44.5" stroke="#000000" stroke-miterlimit="10" width="60" height="446"/> <rect x="644.5" y="9.5" stroke="#000000" stroke-miterlimit="10" width="68" height="471"/> <rect x="736.5" y="18.5" stroke="#000000" stroke-miterlimit="10" width="49" height="462"/> </clipPath> </defs> </svg>
使用
clip-path将定义好的
<clipPath>运用到
<svg>元素上:
svg { clip-path: url(#theSVGPath); }
查看DEMO
更多有关于在SVG上使用
clip-path的示例将会在下面介绍
<clipPath>部分介绍。
一个剪切路径的参考盒子
除了剪切路径本身,还可以给剪切路径应用一个<basic-shape>定义一个剪切路径的参考盒子。也就是说,可以使用一个剪切的基本函数创建一个剪切路径。其中参考盒子只能使用CSS的
clip-path来指定形状路径,而不能使用SVG的
<clipPath>。对于SVG的
<clipPath>参考盒子是一个
border-box元素。
因此剪切路径的参考盒子用
<basic-shape>来指定。如果是一个HTML元素被剪切,可以使用四种盒模型:
margin-box、
border-box、
padding-box和
content-box。每种盒模型都有其自己的解释。
如果
<basic-path>制作的剪切路径运用在一个SVG元素上,参考盒子可以设置为下面三种的其中一种:
fill-box:使用对像的边缘做为参考盒子
stroke-box:使用路径做为参考盒子
view-box:如果没有指定
viewBox将使用最近的SVG视窗做为参考盒子。如果
viewBox的确创建了,则会根据
viewBox的原点坐标和维度来创建参考盒子
如果为SVG元素设置CSS盒模型中的任何一种做为参考盒子,则会使用
fill-box值;如果你使用SVG来做为一个HTML元素的参考盒子,则会使用
border-box盒模型。
.element { clip-path: polygon(...) padding-box; }
如果参考盒子没有使用
clip-path来指定——也就是没有定义任何形状——浏览器将会使用指定的盒子的边缘,包括圆角图形(比如说使用了
border-radius)做为剪切路径。
例如,使用下面的代码片段,使用了
border-radius指定了一个圆角的剪切路径:
.el { clip-path: border-box; border-radius: 25%; }
注意,在写这篇文章之时,使用
border-box指定一个参考盒子,在webkit内核中还无法得以支持,因为它还没有运用于实战当中。
叠加情况、指针事件和动画下的clip-path
的注意事项
特别注意,要知道,如果任何都设置默认值,clip-path属性将会创建一个类似于透明元素。
此外,根据Masking规范,鼠标事件在图形的
clipped-out区域外是无效的。这意味着,如果没有做剪切,鼠标事件还是有效的。这一部规范中做了详细的描述,只是实现方式不同。
绿色区域表示可以响应鼠标事件。左图表示的是标签规范的行为,右图表示非标签规范行为。
为了演示,我在前面示例的基础上,给图片添加了一个
div容器,使用了SVG的
<clipPath>制作剪切路径。如果没有使用剪切,你可以看到图像有边框。添加一个
hover效果,鼠标经过图片时,图片会带有一定的透明度。
如果使用Chrome浏览器(35.0.1916.153版本测试),就算鼠标在图像的剪切之外的区域,图片也会有一琮的透明度。这种行为就是符合标准规范的一种行为。
在Firefox浏览器(30.0版本测试),除了在可视区域图像不会响应鼠标事件。这意味着,鼠标移到图像剪切区域之外,会失去鼠标事件。(图像不带有透明度)
我必须得说,我更喜欢符合规范规范的那种行为,不知道你喜欢的是哪种行为?
查看DEMO
剪切路径还可以使用动画效果。如果使用SVG的
<clipPath>制作剪切路径,可以在其内部设置动画(下一节中将会详细介绍)。如果剪切路径是使用的基本图形函数创建,则何以运用CSS3的
animation或者
transition属性。至于如何使用基本图形创建一个动画的路径,感兴趣的可以阅读我前面写的一篇文章:《Animating CSS Shapes with CSS Animations & Transitions》。
SVG中的剪切——<clipPath>
元素
在SVG中使用<clipPath>元素来定义剪切元素的剪切路径。如果不想使用CSS的
clip-path来定义元素的剪切路径,可以使用SVG中的
clip-path属性。
你看过或读过我写的“Styling and Animating Scalable Vector Graphics with CSS”的幻灯片?如果没有,你应该看看里面介绍的,如何使用SVG的属性和CSS样式来美化SVG元素。你可以点击这里阅读.
<svg> <defs> <clipPath id="myClippingPath"> <!-- ... --> </clipPath> </defs> <!-- the element you want to apply the clipPath to can be any SVG element --> <g id="my-graphic" clip-path="url(#myClippingPath)"> <!-- ... --> </g> </svg>
<clipPath>
的内容
我们前面提到过,可以在SVG中的<clipPath>内创建任意数量的基本形状,
<path>和
<text>元素。它甚至还可以包括很多其他的东西,这正也是SVG很有意思的地方。
<clipPath>元素中的内容可以是描述性的(如
<title>,
<desc>,
<metadata>)。也可以是图形(如:
<circle>,
<ellipse>,
<line>,
<path>,
<polygon>,
<polyline>,
<rect>或者
<text>)。一个
<clipPath>可以包含一个
<use>元素或者
<script>。注意,在
<clipPath>元素中使用
<use>元素,只能引用一些简单的SVG的图形(前面提到的),例如,它在
<clipPath>内不能用于群体的参照,它是没办法正常工作的。
最后一部分,但并不是最重要的一部分。
<clipPath>可以包括一个使用
<animate>,
<animateColor>,
<animateMotion>,
<animateTransform>或
<set>创建的动画。这为很多创造打开了一扇门,只要你敢想,就能做。
使用多个
<circle>制作的剪路径,并且添加了一个简单的动画效果来做为示例演示。每个
<circle>都有一个简单的动画。为了保证示例的简单,在所有圆上都使用了同一个简单的动画效果。当然,你可以为每个圆创建不同的动画效果。演示示例的代码如下:
<svg height="0" width="0"> <defs> <clipPath id="svgPath"> <circle stroke="#000000" stroke-miterlimit="10" cx="50" cy="50" r="40"> <animate attributeName="r" attributeType="XML" from="0" to="250" begin="0s" dur="3s" fill="freeze" repeatCount="indefinite"/> </circle> <circle stroke="#000000" stroke-miterlimit="10" cx="193.949" cy="235" r="74.576"> <animate attributeName="r" attributeType="XML" from="0" to="250" begin="0s" dur="3s" fill="freeze" repeatCount="indefinite"/> </circle> <!-- ... --> </clipPath> </defs> </svg>
这个动画就只指定了每个圆的尺寸大小,圆的半径从0到250px,总共花了3秒时间,并且设置了动画播放次数是无限次。
点击下面的按钮查看示例,使用Chrome或者Safari点击查看案例之前,得告诉您,示例还存在一个bug(详细介绍请点击这里),所以我建议您使用Firefox查看示例,直到这个Bug已修复。
查看DEMO
请注意,
<clipPath>的内容也不能包括
<g>。例如我们给多个圆
<circle>放在一个组里
<g>,那么它不能正常工作,剪切路径不会运用到图片上。
<svg height="0" width="0"> <defs> <clipPath id="svgPath"> <!-- WILL NOT WORK --> <g> <!-- WILL NOT WORK --> <circle stroke="#000000" stroke-miterlimit="10" cx="193.949" cy="235" r="74.576"/> <circle stroke="#000000" stroke-miterlimit="10" cx="426.576" cy="108.305" r="47.034"/> <!-- ... --> </g> </clipPath> </defs> </svg>
clipPathUnits
属性
<clipPath>元素包括很多个属性,比如
id,
class,
transform和像
fill和
stroke这样的显示属性以及其他更多属性。其中最有用的是
clipPathUnits属性。
clipPathUnits主要用来给
<clipPath>元素内容指定一个坐标系统。它具有两个值:
objectBoundingBox和
userSpaceOnUse,其中
userSpaceOnUse是默认值。
clipPathUnits = "userSpaceOnUse | objectBoundingBox"
userSpaceOnUse
当clipPath元素是用来当作参考物时,
clipPath元素内容是以用户坐标系统作为参考点。(例如:
clipPath元素的用户坐标系统是通过
clip-path属性来引用)。
用户坐标系统(局部坐标系统)是目前激活的坐标系统,主要用来如何定位坐标和长度。一个HTML元素的坐标和CSS的盒模型有关,但不同的是SVG元素没有这样的盒模型。
对于CSS盒子的布局,用户的坐标原点就在盒子的左上角,而且一个单位就是一个像素,视窗也可以根据盒子的宽度按百分比计算。我想你对这方面应该非常的熟悉。如果你有一个
<clipPath>元素包含了一个
<circle>,而且这个
<circle>的中心点在
cx=100和
cy=100。那么这个中心点就是距盒子左边100px和顶边100px的交汇处。
如果元素是一个SVG元素,因此他是没一个类似于CSS盒模型的东西,用户的坐标原点是距
<svg>元素视窗左上角最近的一个地方。一般情况之下,最近的视窗的建立,他的宽度和高度接近于
<svg>的祖先元素。如果你不嵌套
<svg>元素,它就是你创建的
<svg>元素。
注意,SVG元素的坐标系统可以使用
viewBox属性进行修改,其他属性可能有助于改变坐标系统。这一部分的内容超出了本文的内容范围。所以在本文中,我假设
viewBox没有进行过任何的修改。因此浏览器使用的默认坐标系统原点是在
<svg>元素的左上角,大小也等于
<svg>元素。
objectBoundingBox
坐标系统的原点是在元素的边框盒子的左上角顶点处,同样适于剪切路径。这个边框是SVG元素对象的边框(它只是包含了一个或多个几何图形形状)和一个HTML元素设置border-box的盒模型是相关联的。
这个值对
SVG元素非常有用,因为它允许你应用的元素自身的边界做为剪切路径。下图显示一个图像应用SVG的剪切路径显示的效果,他们分别使用了
userSpaceOnUse和
objectBoundingBox。灰色的边框表示的是
SVG元素创建的一个视窗。右图中的图像,我添加了一个灰色的边框用来表示剪切后的图像边框。
在左图中,剪切路径的坐系统定位在SVG的视窗上。当使用了
objectBoundingBox属性之后,图像自身的边框就会做为剪切路径的坐标系统。
有一点需要特别的注意:当你设置了
objectBoundingBox值后,
<clipPath>元素中的内容必须在指定的坐标[0,1]内。坐标系统将成为一个单元系统,剪切出来的形状都在这个
clipPath分值内。
例如,如果剪切路径包含一个
<circle>元素,而且他定位在圆的中心上:
<clipPath> <circle cx="350" cy="350" r="300" /> </clipPath>
圆的位置(半径)会用分数表示:
<clipPath clipPathUnits="objectBoundingBox"> <circle cx=".5" cy=".5" r=".45" /> </clipPath>
在这种情况下,分数就像百分比。
<clipPath>
笔记
<clipPath>元素不会直接在页面上呈现,他唯一的作用就是可以通过
clip-path来引用。
display属性不能运用于
<clipPath>元素上,因此,就算
display设置
none外的其他值,
<clipPath>元素也不会直接呈现。
还记得我前面提到HTML元素剪切后的鼠标事件吗?相同的标准定义的行为却不同。鼠标事件在SVG的剪切区域外是无效。规范后面提到,可以让SVG定义新属性来控制剪切。
Firefox浏览器实现了相同非标准行为,在剪切区域之外不支持鼠标事件。
尽管Chrome为HTML元素的
clip-path属笥实现标准行为,当你在一个
<svg>元素上使用
<clipPath>时,实现的行为是一样的。只有Firefox在可视区域能响应鼠标事件,我不知道这是一个特性还是一个Bug。
在接下来的示例中,一个SVG的
<clipPath>应用在一个SVG的
<image>上。这个剪切路径我们前面使用过,图像剪成很多个矩形。当你的鼠标悬浮在图像上,图像具有一定的透明度。
image { clip-path: url(#svgPath); } image:hover { opacity: .5; }
查看DEMO
请注意,一个空的剪切路径同样会被
clip-path应用在元素上。
总结
剪切是一种图形化操作,允许我们在一个矩形的页面中创建不规则图形。实际上剪切和CSS的Shapes是一对完美的搭档。如果你有阅读过我早前写的关于CSS的Shapes的文章,你就会看到很多实例中使用了clip-path属性。一旦CSS的Shapes可以运用于SVG的路径上(CSS Shapes Module Level 2),除了CSS的基本形状之外,CSS的Shapes和剪切配合可以让我们在视觉上制作出引人注目的设计,打破矩形的限制。
我希望这篇文章对你有所帮助,感谢您的阅读。
译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!
如需转载烦请注明出处:
英文原文:http://sarasoueidan.com/blog/css-svg-clipping/
中文译文:http://www.w3cplus.com/css3/css-svg-clipping.html
相关文章推荐
- CSS3制作炫酷的下拉菜单及弹起式选单的实例分享
- webpack分离css单独打包
- css固定div头部不随滚动条滚动
- CSS选择器的权重与优先规则
- CSS3中各种颜色属性的使用教程
- 使用CSS3美化HTML表单的技巧演示
- css控制滚动条样式
- 实现QQ空间评论列表样式
- CSS基础选择器温故-1
- 利用CSS3的border-radius绘制太极及爱心图案示例
- CSS flex
- CSS3的REM设置字体大小
- CSS学习之Layouts方法float - CSS: The Missing Manual
- css 的居中问题集锦
- css实现两端对齐
- css实现ie6以上文字高度未知垂直居中
- css3新增属性
- CSS选择器优先级
- js去除所有标签行内样式
- js获取非行间样式