zoukankan      html  css  js  c++  java
  • CSS和SVG中的剪切——clip-path属性和<clipPath>元素

    剪切是什么

    剪切是一个图形化操作,你可以部分或者完全隐藏一个元素。被剪切的元素可以是一个容器也可以是一个图像元素。元素的哪些部分显示或隐藏是由剪切的路径来决定的。

    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);
    }

    应用上面的代码之后,图像显示成这样:

    CSS和SVG中的剪切

    查看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>
    

    这剪切路径看起来就像一个黑色的描边圈了一个不规则的图形,这是一个简单的剪切路径,不带有任何的填充。

    CSS和SVG中的剪切

    在下一部分中,我们将着重讨论SVG的<clipPath>元素。但现在,我们来看看如何将定义好的路径运用到图片上:

    img {
        clip-path: url(#svgPath);
    }

    最终效果如下所示:

    CSS和SVG中的剪切

    查看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属性,将文本的宽度设置的和图片宽度一样, 并且通过xy来定位文本。注意,xy坐标确认了文本左下角的位置(也就是文本的基线baseline)。

    使用上面的文本路径剪切图来的图片效果如下:

    CSS和SVG中的剪切

    查看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>
    

    此时,图像只会在圆中显示,圆外就不会显示:

    CSS和SVG中的剪切

    查看DEMO

    正如我们这篇文章中介绍的,你可以使用clip-path属性应用在SVG元素绘制的路径。在上面演示的示例,剪切路径都是应用在HTML中的<img>元素上。在接下来的示例中,将演示的是一个剪切路径用于<svg>的根元素。同样是樱花图片,使用下面SVG的中的<image>来引用。

    SVG中的<image>元素用来引用一个完整的SVG或像素图像。如果你在<image>中引用的SVG图像,设置的widthheight属性,将会用来设置SVG视窗的大小。如果你引用的是像素图像(我们这里的例子就是这样做的),图像将会自动缩放到指定的widthheight。所以我们要确认好他们的长宽比例,避免图像扭曲。

    当你创建一个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);
    }

    CSS和SVG中的剪切

    查看DEMO

    更多有关于在SVG上使用clip-path的示例将会在下面介绍<clipPath>部分介绍。

    一个剪切路径的参考盒子

    除了剪切路径本身,还可以给剪切路径应用一个<basic-shape>定义一个剪切路径的参考盒子。也就是说,可以使用一个剪切的基本函数创建一个剪切路径。其中参考盒子只能使用CSS的clip-path来指定形状路径,而不能使用SVG的<clipPath>。对于SVG的<clipPath>参考盒子是一个border-box元素。

    因此剪切路径的参考盒子用<basic-shape>来指定。如果是一个HTML元素被剪切,可以使用四种盒模型:margin-boxborder-boxpadding-boxcontent-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区域外是无效的。这意味着,如果没有做剪切,鼠标事件还是有效的。这一部规范中做了详细的描述,只是实现方式不同。

    CSS和SVG中的剪切

    绿色区域表示可以响应鼠标事件。左图表示的是标签规范的行为,右图表示非标签规范行为。

    为了演示,我在前面示例的基础上,给图片添加了一个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和像fillstroke这样的显示属性以及其他更多属性。其中最有用的是clipPathUnits属性。

    clipPathUnits主要用来给<clipPath>元素内容指定一个坐标系统。它具有两个值:objectBoundingBoxuserSpaceOnUse,其中userSpaceOnUse是默认值。

    clipPathUnits = "userSpaceOnUse | objectBoundingBox"

    userSpaceOnUse

    clipPath元素是用来当作参考物时,clipPath元素内容是以用户坐标系统作为参考点。(例如:clipPath元素的用户坐标系统是通过clip-path属性来引用)。

    用户坐标系统(局部坐标系统)是目前激活的坐标系统,主要用来如何定位坐标和长度。一个HTML元素的坐标和CSS的盒模型有关,但不同的是SVG元素没有这样的盒模型。

    对于CSS盒子的布局,用户的坐标原点就在盒子的左上角,而且一个单位就是一个像素,视窗也可以根据盒子的宽度按百分比计算。我想你对这方面应该非常的熟悉。如果你有一个<clipPath>元素包含了一个<circle>,而且这个<circle>的中心点在cx=100cy=100。那么这个中心点就是距盒子左边100px和顶边100px的交汇处。

    如果元素是一个SVG元素,因此他是没一个类似于CSS盒模型的东西,用户的坐标原点是距<svg>元素视窗左上角最近的一个地方。一般情况之下,最近的视窗的建立,他的宽度和高度接近于<svg>的祖先元素。如果你不嵌套<svg>元素,它就是你创建的<svg>元素。

    注意,SVG元素的坐标系统可以使用viewBox属性进行修改,其他属性可能有助于改变坐标系统。这一部分的内容超出了本文的内容范围。所以在本文中,我假设viewBox没有进行过任何的修改。因此浏览器使用的默认坐标系统原点是在<svg>元素的左上角,大小也等于<svg>元素。

    objectBoundingBox

    坐标系统的原点是在元素的边框盒子的左上角顶点处,同样适于剪切路径。这个边框是SVG元素对象的边框(它只是包含了一个或多个几何图形形状)和一个HTML元素设置border-box的盒模型是相关联的。

    这个值对SVG元素非常有用,因为它允许你应用的元素自身的边界做为剪切路径。下图显示一个图像应用SVG的剪切路径显示的效果,他们分别使用了userSpaceOnUseobjectBoundingBox。灰色的边框表示的是SVG元素创建的一个视窗。右图中的图像,我添加了一个灰色的边框用来表示剪切后的图像边框。

    CSS和SVG中的剪切

    在左图中,剪切路径的坐系统定位在SVG的视窗上。当使用了objectBoundingBox属性之后,图像自身的边框就会做为剪切路径的坐标系统。

    有一点需要特别的注意:当你设置了objectBoundingBox值后,<clipPath>元素中的内容必须在指定的坐标[0,1]内。坐标系统将成为一个单元系统,剪切出来的形状都在这个clipPath分值内。

    CSS和SVG中的剪切

    例如,如果剪切路径包含一个<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

  • 相关阅读:
    PHP 大小写转换、首字母大写、每个单词首字母大写转换相关函数
    【论文学习4】BiSample: Bidirectional Sampling for Handling Missing Data with Local Differential Privacy
    【论文学习3】Local Differential Privacy for Deep Learning
    【论文学习2】 Differential Privacy Reinforcement Learning
    深度学习中的优化算法
    Spatial crowdsourcing
    “pip install tensorflow ”出现错误
    python或pip'不是内部或外部命令”
    pip install torch出现错误
    打不开gitHub的解决方法
  • 原文地址:https://www.cnblogs.com/Alex80/p/4210733.html
Copyright © 2011-2022 走看看