clip-rule

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2020 年 1 月⁩ 起,所有主流浏览器均已支持。

clip-rule CSS 属性用于确定,当路径的某些部分重叠其他部分时,遮罩框中哪些像素位于由 剪裁路径(clip path)定义的剪裁形状内部,哪些像素位于外部。

clip-rule 属性仅适用于包含在 <clipPath> 元素内的 SVG 元素,如果存在,它会覆盖该元素的 clip-rule 属性值。clip-rule 属性的工作方式与 fill-rule 属性基本相同,只是它应用于 <clipPath> 定义。它对 CSS <basic-shape> 没有任何影响。

语法

css
/* Keywords */
clip-rule: nonzero;
clip-rule: evenodd;

/* Global values */
clip-rule: inherit;
clip-rule: initial;
clip-rule: revert;
clip-rule: revert-layer;
clip-rule: unset;

nonzero

对于剪裁遮罩框中的每个点,都会向随机方向绘制一条射线。每当射线与剪裁路径的任何部分相交时,如果剪裁路径的部分从左向右穿过射线,计数会增加一;如果路径部分从右向左穿过射线,计数会减少一。如果最终计数总和为零,则该点位于路径形状之外。否则,它位于路径形状之内。

even-odd

对于剪裁遮罩框中的每个点,都会向随机方向绘制一条射线。每当射线与剪裁路径的任何部分相交时,计数会增加一。如果最终计数总和为偶数,则该点位于路径形状之外;否则,它位于路径形状之内。零被视为偶数。

正式语法

clip-rule = 
nonzero |
evenodd

示例

值比较

在此示例中,我们将不同的 CSS clip-rule 值应用于类似的 SVG <path> 元素,以演示 evenoddnon-zero 之间的区别。

HTML

标记包含多个 <svg> 容器,每个容器都包含一个定义星形轮廓的 <clipPath> 元素,以及一个用于在其中绘制星形的 <rect> 元素。星形由重叠的线条创建。除了 id 之外,前两个 SVG 元素的标记是相同的。第三个 SVG 只包含 <path> 元素,显示了创建星形的路径线条如何重叠。

html
<svg>
  <clipPath id="star1">
    <path d="M50,0 21,90 98,35 2,35 79,90z" />
  </clipPath>
  <rect clip-path="url(#star1)" width="95" height="95" />
</svg>

<svg>
  <clipPath id="star2">
    <path d="M50,0 21,90 98,35 2,35 79,90z" />
  </clipPath>
  <rect clip-path="url(#star2)" width="95" height="95" />
</svg>

<svg id="star3">
  <path d="M50,0 21,90 98,35 2,35 79,90z" />
</svg>

CSS

第一个 SVG 中 <path>clip-rule 设置为 evenodd;第二个 SVG 中设置为 nonzero。对于仅包含路径的 SVG,我们移除了默认的 fill,并定义了 stroke 颜色和 stroke-width,以使重叠的路径线条可见。

css
#star1 path {
  clip-rule: evenodd;
}

#star2 path {
  clip-rule: nonzero;
}

#star3 path {
  fill: none;
  stroke: black;
  stroke-width: 1;
}

结果

在基本形状定义中

此示例演示了,尽管 clip-rule 对 CSS <basic-shape> 没有影响,但它会影响用作形状来源的 <clipPath>

HTML

我们包含一个 SVG,其中包含两个定义星形的 <clipPath> 元素,它们除了 id 属性值外,其他都相同。我们还包含两个将包含星形形状的 <div> 元素。

html
<svg height="0" width="0">
  <defs>
    <clipPath id="star1">
      <path d="M100,0 42,180 196,70 4,70 158,180z" />
    </clipPath>
    <clipPath id="star2">
      <path d="M100,0 42,180 196,70 4,70 158,180z" />
    </clipPath>
  </defs>
</svg>

<div></div>
<div></div>

CSS

我们为 <div> 元素设置了 widthheight,并添加了 conic-gradient() 作为它们的 background-image 值。

css
div {
  height: 200px;
  width: 200px;
  background-image: conic-gradient(
    at center,
    rebeccapurple,
    green,
    lightblue,
    rebeccapurple
  );
}

我们使用 clip-path 属性将不同的 <clipPath> 元素设置为每个 <div> 的剪裁路径。

css
div:first-of-type {
  clip-path: url("#star1");
}
div:last-of-type {
  clip-path: url("#star2");
}

最后,我们为每个 <clipPath> 元素的 <path> 设置了不同的 clip-rule 值。

css
#star1 path {
  clip-rule: evenodd;
}
#star2 path {
  clip-rule: nonzero;
}

结果

选择所有顺时针路径的路径规则

在此 SVG 图像中,我们有两个被剪裁的矩形,每个矩形都使用一种剪裁规则。有两个 <clipPath> 元素,这样可以一个设置为使用非零剪裁规则,另一个设置为使用奇偶规则。两个路径的内部和外部部分都以顺时针方向绘制。

html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 50">
  <g stroke="#112233" fill="#bbccdd">
    <!-- basic rectangle and clipping path visualization follow -->
    <rect x="10" y="10" width="30" height="30" />
    <path
      d="M 65,5 l 20,20 -20,20 -20,-20 20,-20 m 0,10 l 10,10 -10,10 -10,-10 10,-10 z"
      fill="none"
      stroke-width="0.5" />
    <!-- rectangles to be clipped follow -->
    <rect x="110" y="10" width="30" height="30" clip-path="url(#clipper1)" />
    <rect x="160" y="10" width="30" height="30" clip-path="url(#clipper2)" />
  </g>
  <!-- clipping paths follow -->
  <clipPath id="clipper1" clipPathUnits="objectBoundingBox">
    <path
      d="M 0.5 -0.15 l 0.65 0.65 -0.65,0.65 -0.65,-0.65 0.65,-0.65 m 0,0.33 l 0.33,0.33 -0.33,0.33 -0.33,-0.33 0.33,-0.33 z"
      clip-rule="evenodd" />
  </clipPath>
  <clipPath id="clipper2" clipPathUnits="objectBoundingBox">
    <path
      d="M 0.5 -0.15 l 0.65 0.65 -0.65,0.65 -0.65,-0.65 0.65,-0.65 m 0,0.33 l 0.33,0.33 -0.33,0.33 -0.33,-0.33 0.33,-0.33 z"
      clip-rule="nonzero" />
  </clipPath>
</svg>

对于应用于剪裁矩形的剪裁路径,使用 CSS clip-rule 属性将一个路径设置为使用 nonzero 规则,另一个设置为使用 evenodd 规则。这些规则覆盖了 SVG 中 clip-path 属性的值,这些值已被有意设置为与 CSS 施加的值相反。

css
#clipper1 {
  clip-rule: nonzero;
}
#clipper2 {
  clip-rule: evenodd;
}

由于路径的内部和外部部分都以顺时针(从左到右)方向移动,因此两种剪裁规则产生的剪裁形状将不同。对于 nonzero,形状外部部分内的任何射线都将计数为大于零的值,因为它将遇到一个或多个从左到右的路径片段。对于 even-odd,路径两部分之间的点将具有奇数计数,而内部路径内部或外部部分外部的任何点将具有偶数计数。

为具有不同缠绕路径的路径选择规则

此示例使用与上一个示例相同的 SVG,不同之处在于剪裁路径的内部部分以逆时针方向缠绕。

html
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 50">
  <g stroke="#112233" fill="#bbccdd">
    <!-- basic rectangle and clipping path visualization follow -->
    <rect x="10" y="10" width="30" height="30" />
    <path
      d="M 65,5 l 20,20 -20,20 -20,-20 20,-20 m 0,10 l 10,10 -10,10 -10,-10 10,-10 z"
      fill="none"
      stroke-width="0.5" />
    <!-- rectangles to be clipped follow -->
    <rect x="110" y="10" width="30" height="30" clip-path="url(#clipper1)" />
    <rect x="160" y="10" width="30" height="30" clip-path="url(#clipper2)" />
  </g>
  <!-- clipping paths follow -->
  <clipPath id="clipper1" clipPathUnits="objectBoundingBox">
    <path
      d="M 0.5 -0.15 l 0.65 0.65 -0.65,0.65 -0.65,-0.65 0.65,-0.65 m 0,0.33 l -0.33,0.33 0.33,0.33 0.33,-0.33 -0.33,-0.33 z" />
  </clipPath>
  <clipPath id="clipper2" clipPathUnits="objectBoundingBox">
    <path
      d="M 0.5 -0.15 l 0.65 0.65 -0.65,0.65 -0.65,-0.65 0.65,-0.65 m 0,0.33 l 0.33,0.33 -0.33,0.33 -0.33,-0.33 0.33,-0.33 z" />
  </clipPath>
</svg>

我们应用与之前相同的 CSS。

css
#clipper1 {
  clip-rule: nonzero;
}
#clipper2 {
  clip-rule: evenodd;
}

在这种情况下,由于路径的外部部分以顺时针(从左到右)方向移动,而路径的内部部分以逆时针(从右到左)方向移动,因此无论使用哪种剪裁规则,产生的剪裁形状都将相同。

规范

规范
CSS 蒙版模块 Level 1
# the-clip-rule

浏览器兼容性

另见