CSS 裁剪简介

CSS 裁剪可以让你定义元素的可见部分,同时隐藏其他部分,从而有效地将元素内容“裁剪”成特定的形状或区域。通过裁剪,元素不再局限于渲染成矩形,可以设计出更具视觉吸引力的样式。本指南将探讨 clip-path 属性以及一些示例。

CSS 裁剪

裁剪是一种 CSS 技术,用于剪切(隐藏)元素的部分区域,仅显示位于开发者定义的路径内的元素区域。剪切区域由矢量路径创建;路径内的任何内容都可见,而路径外的内容则被隐藏。

clip-path 属性

clip-path 属性用于应用裁剪。它接受的值是一个矢量路径,定义了元素中应该保持可见的区域。该路径可以使用盒子(box)、对 SVG <clipPath> 的引用或 CSS 形状和路径来定义。在下面的示例中,我们使用 polygon() 函数作为裁剪路径,将一个蓝色的方形 <div> 裁剪成一个菱形。

css
.diamond {
  height: 200px;
  width: 200px;
  background-color: blue;

  clip-path: polygon(0 50%, 50% 100%, 100% 50%, 50% 0);
}

通过 clip-path 属性,你可以将元素裁剪为 <basic-shape>SVG 源,从而创建复杂的形状。如果声明的各个状态具有相同数量的矢量点,你还可以对 clip-path 形状进行动画和过渡

clip-path 属性的值

要对元素进行视觉裁剪,clip-path 属性可以设置为一个 <geometry-box>、一个指向 <clipPath> 裁剪源的 url,或一个用形状函数创建的 <basic-shape>

几何盒子

clip-path 会隐藏裁剪区域之外的所有内容。最基本的裁剪是通过几何盒子完成的。你可以根据元素的外边距、边框、内边距或内容进行裁剪。这些视觉盒子值的效果可以通过其他 CSS 属性实现,例如将 border-color 设置为透明,并将 background-origin 设置为所需的视觉盒子。我们主要关注这些值,是因为它们与我们稍后将要讨论的形状函数结合使用,以定义形状裁剪路径的原点。

在使用 clip-path 时,特别是与基本形状一起使用时,理解 CSS 形状所使用的参考盒非常重要,因为参考盒定义了形状的坐标系。

视觉盒子值

这个实时示例演示了 clip-path 属性对一个元素的不同视觉盒子值的效果,并将其与 CSS background-origin 属性进行比较。我们对 <blockquote> 应用了 borderbackground-colorbackground-imagepadding。选择一个单选按钮来将 --value 更新为不同的 <geometry-box> 值,这将更新 background-originclip-path 的解析值。

css
blockquote {
  width: 210px;
  padding: 20px;
  margin: 20px;
  border: 20px dashed #dedede;
  background-color: #ededed;
  background-image: linear-gradient(rebeccapurple, magenta);
  background-repeat: no-repeat;
}

.clippath {
  background-origin: var(--value);
  clip-path: var(--value);
}

.box-model {
  background-origin: var(--value);
}

<geometry> 盒子与 <basic-shape> 结合指定时,该值定义了基本形状的参考盒。如果单独指定,它将使指定盒子的边缘(包括任何圆角效果,如 border-radius)成为裁剪路径。

形状原点

前面的示例可能会让你觉得 <geometry-box> 值没什么用,因为你可以用 background-origin 来代替。确实可以。但是,在使用基本形状进行裁剪时,如果 <geometry-box><basic-shape> 一起作为 clip-path 的值,它就定义了该形状的参考盒或原点。我们可以结合前面两个示例来演示这一点。

css
blockquote {
  width: 210px;
  padding: 20px;
  margin: 20px;
  border: 20px dashed #dedede;
  background-color: #ededed;
  background-image: linear-gradient(rebeccapurple, magenta);
  background-repeat: no-repeat;
  background-origin: border-box;
  clip-path: var(--value) polygon(0 50%, 50% 100%, 100% 50%, 50% 0);
}

另一个示例,请参阅 clip-path 形状和几何盒子

即使像 clip-path: margin-box 这样的值也很有用。除了通过将裁剪路径的边缘置于外边距盒边缘来创造视觉效果外,clip-path 的任何非 none 的计算值都会创建一个新的层叠上下文,就像 CSS opacity 属性在值不为 1 时所做的那样。

裁剪为基本形状

clip-path 属性对 <basic-shape> 值的支持提供了一种强大的元素塑形方式。各种形状函数可以定义精确的裁剪区域,有效地将元素塑造成独特的形态。基本形状函数包括:

这些形状的大小和位置由 <geometry-box> 值定义,如果 clip-path 值包含一个形状但没有 <geometry-box> 组件值,则默认使用 border-box 作为参考盒。

其中一些函数似乎只提供基本的预定义裁剪选项。它们可能看起来只是复制了你可以用 border-radius 创建的效果,但如果你在前面的示例中切换了 border-radius 属性,你可能已经注意到了 CSS 裁剪的强大之处。形状提供了更多的控制。例如,inset() 允许用精确的外边距来裁剪一个矩形。而真正的强大和控制力来自于 path()shape() 甚至 polygon(),它们允许创建自定义的多点形状。

创建多边形

使用 polygon(),通过定义代表形状每个顶点的坐标对,你可以创建复杂的形状,如星星或抽象图形。这些坐标定义了由直线连接的矢量点。

这里我们使用 polygon() 函数来创建一个星星:

css
.star {
  width: 200px;
  height: 200px;
  background: linear-gradient(rebeccapurple, magenta) blue;
  clip-path: polygon(
    50% 0%,
    61% 35%,
    100% 35%,
    68% 57%,
    79% 91%,
    50% 70%,
    21% 91%,
    32% 57%,
    0% 35%,
    39% 35%,
    50% 0%
  );
}

Animation

通过为不同状态声明相同数量的矢量点,可以对裁剪的形状进行动画和过渡。

css
@keyframes morphStar {
  from {
    clip-path: polygon(
      50% 0%,
      61% 35%,
      100% 35%,
      68% 57%,
      79% 91%,
      50% 70%,
      21% 91%,
      32% 57%,
      0% 35%,
      39% 35%,
      50% 0%
    );
  }
  to {
    clip-path: polygon(
      50% 10%,
      65% 30%,
      90% 20%,
      75% 60%,
      85% 95%,
      50% 80%,
      15% 95%,
      25% 60%,
      10% 20%,
      35% 30%,
      50% 10%
    );
  }
}

.star {
  animation: morphStar alternate 3s infinite ease-in-out;
}

path() 函数

path() 函数可以使用 SVG 命令来绘制形状。该函数接受与 SVG d 属性等效的字符串作为其参数。

前一个示例中的星星可以用 path() 来创建:

css
.star {
  width: 200px;
  height: 200px;
  background: linear-gradient(rebeccapurple, magenta) blue;
  clip-path: path(
    "M100,0 L122,70 L200,70 L136,114 L158,182 L100,140 L42,182 L64,114 L0,70 L78,70 L100,0 Z"
  );
}

曲线

使用 path(),我们不局限于直线。在这个例子中,我们使用 path() 函数来创建一个心形:

css
.heart {
  width: 200px;
  height: 200px;
  background: linear-gradient(rebeccapurple, magenta) blue;
  clip-path: path(
    "M20,70 A40,40,0,0,1,100,70 A40,40,0,0,1,180,70 Q180,130,100,190 Q20,130,20,70 Z"
  );
}

将 SVG 作为源

除了将 SVG d 属性字符串作为 path() 函数的参数传递外,clip-path 属性的值还可以直接引用 SVG <clipPath> 元素。

html
<div class="heart"></div>
<svg height="0" width="0">
  <clipPath id="heart">
    <path
      d="M20,70 A40,40,0,0,1,100,70 A40,40,0,0,1,180,70 Q180,130,100,190 Q20,130,20,70 Z" />
  </clipPath>
</svg>

<clipPath>idurl() 函数的参数。

css
.heart {
  width: 200px;
  height: 200px;
  background: linear-gradient(rebeccapurple, magenta) blue;
  clip-path: url("#heart");
}

shape() 函数

SVG 路径语法并不是最直观的。因此,CSS 还提供了 shape() 函数。shape() 函数也接受路径绘制指令,但其语法更易于人类阅读。我们可以用更具声明性的 CSS 来重现心形:

css
.heart {
  clip-path: shape(
    from 20px 70px,
    arc to 100px 70px of 1% cw,
    arc to 180px 70px of 1% cw,
    curve to 100px 190px with 180px 130px,
    curve to 20px 70px with 20px 130px
  );
}

shape() 函数更为强大,因为它接受 CSS 的值和单位(path() 仅限于坐标),包括使用像 calc() 这样的 CSS 数学函数。通过使用变量,我们可以创建多种不同大小的形状(和盒子):

css
:root {
  --m: 10;
}
.heart {
  width: calc(20px * var(--m));
  height: calc(20px * var(--m));
  display: inline-block;
  background: linear-gradient(rebeccapurple, magenta) blue;
  clip-path: border-box
    shape(
      from calc(2px * var(--m)) calc(7px * var(--m)),
      arc to calc(10px * var(--m)) calc(7px * var(--m)) of 1% cw,
      arc to calc(18px * var(--m)) calc(7px * var(--m)) of 1% cw,
      curve to calc(10px * var(--m)) calc(19px * var(--m)) with
        calc(18px * var(--m)) calc(13px * var(--m)),
      curve to calc(2px * var(--m)) calc(7px * var(--m)) with
        calc(2px * var(--m)) calc(13px * var(--m))
    );
}
.small {
  --m: 4;
}

.medium {
  --m: 8;
}

.large {
  --m: 12;
}
html
<div class="heart small"></div>
<div class="heart medium"></div>
<div class="heart large"></div>

让文本环绕裁剪的形状

被裁剪的元素仍然是矩形盒子。裁剪意味着你的元素看起来不像一个盒子,但它仍然是一个盒子。要让内联内容环绕你定义的非矩形(或矩形)形状,请使用 shape-outside 属性。默认情况下,内联内容会环绕其外边距盒;shape-outside 提供了一种自定义这种环绕的方式,使得文本可以围绕你裁剪的元素,并遵循你复制的裁剪路径,而不是元素的矩形盒子。

内容包括两个要裁剪的元素,以及将围绕它们进行塑形的文本。

html
<div class="leftTriangle"></div>
<div class="rightTriangle"></div>
<blockquote>
  <q>
    I've learned that people will forget what you said, people will forget what
    you did, but people will never forget how you made them feel.</q
  >
  <cite>&mdash; Maya Angelou</cite>
</blockquote>

除了为 clip-shapeshape-outside 属性应用相同的形状外,被裁剪的元素还必须进行浮动,以便它与内容位于同一行。

css
.leftTriangle {
  clip-path: polygon(0 0, 0 100%, 100% 0);
  shape-outside: polygon(0 0, 0 100%, 100% 0);
  float: left;
}
.rightTriangle {
  clip-path: polygon(100% 0, 100% 100%, 0 100%);
  shape-outside: polygon(100% 0, 100% 100%, 0 100%);
  float: right;
}

另见