CSS和SVG有很多共同之处。CSS有很多特性都是从SVG中引入过来的。其中就有“剪切”的特性。CSS和SVG都允许我们对一个元素进行非矩形的剪切。在这篇文章中,将介绍CSS和SVG中的剪切技术。
特别声明:本文提供的DEMO可能在你的浏览器中不能正常的演示,你应该查看这个表格了解更多相关的信息。你在阅读这篇文章之时没有必要查看提供的DEMO。不是所有的剪切特性都可以实现或者说只能实现部分剪切特性。本文的最大目的是告诉你CSS和SVG中的剪切是如何工作?仅用来做为参考。在文章中的代码不带有任何浏览器的私有前缀,但在示例中还是带了浏览器的私有前缀。
剪切是什么
剪切是一个图形化操作,你可以部分或者完全隐藏一个元素。被剪切的元素可以是一个容器也可以是一个图像元素。元素的哪些部分显示或隐藏是由剪切的路径来决定的。
剪切路径定义了一个区域,在这个区域内的内容将会显示,而不在这个区域内的内容不会显示。这个区域被称之为“裁剪区域”。只要在这个区域之外的任何元素都不会显示。包括元素的内容、背景、边框、文本、轮廓等,甚至还包括他的子元素。
剪切的元素可以是任何容器和图片元素。
剪切路径的概念就相当于在元素上定义了一个视窗。它决定了元素哪些部分在这个“视窗”中显示,哪些部分不在这个“视窗”中显示。但他不会影响自身文档流和其他文档流,因为他通常还是以一个矩形区域显示在其他文档流前面,哪怕是剪切出来的区域是不规则的矩形。如果你想改变周围内容元素围绕剪切出来的图形,那就需要使用CSS的图形属性。如果你对这方面知识感兴趣,可以阅读我早前写的相关文章。
有关于CSS3 Shapes相关中文教程,可以阅读早前翻译的两篇文章:
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);
}
应用上面的代码之后,图像显示成这样:
基本图形函数允许我们创建一定数量的图形,其中最复杂的就是多边形。如果你想创建一个更为复杂的图形,而且图形看起来不是用直线画出来的,这个时候你就需要使用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);
}
最终效果如下所示:
事实上,<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)。
使用上面的文本路径剪切图来的图片效果如下:
正如我们前面提到的,你还可以在<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>
此时,图像只会在圆中显示,圆外就不会显示:
正如我们这篇文章中介绍的,你可以使用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"