使用 Clip-Path 进行动画

Avatar of Travis Almand
Travis Almand

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费积分!

clip-path 是 CSS 属性中的一种,我们通常都知道它存在,但可能出于某种原因并没有经常使用。 因为它涉及到使用几何形状,并且每个形状都有不同的值来以特定方式绘制特定形状,所以它有点让人望而生畏,感觉就像数学课。

在本文中,我们将深入探讨 clip-path,重点介绍如何使用它来创建相当复杂的动画。 我希望您会看到这个属性及其形状变换功能是多么棒。

但首先,让我们快速回顾一下我们正在使用的内容。

Clip-path 快速入门

为了快速解释 clip-path 是什么以及它提供了什么,MDN 描述如下 这里

clip-path CSS 属性创建了一个裁剪区域,该区域设置元素的哪个部分应显示。 区域内的部分将显示,而区域外的部分将隐藏。

考虑 clip-path 提供的 circle 形状。 一旦定义了圆形,圆形内部的区域可以被认为是“正的”,而圆形外部的区域可以被认为是“负的”。 正空间将被渲染,而负空间将被移除。 利用正空间和负空间之间这种关系可以进行动画,从而提供有趣的过渡效果……这正是我们接下来要介绍的内容。

clip-path 随附四个开箱即用的形状,以及使用 URL 为其他 SVG <clipPath> 元素提供来源的能力。 我将让 CSS-Tricks 年鉴 深入讨论,但以下是一些前四个形状的示例。

形状 示例 结果
圆形 clip-path: circle(25% at 25% 25%);
椭圆形 clip-path: ellipse(25% 50% at 25% 50%);
内嵌 clip-path: inset(10% 20% 30% 40% round 25%);
多边形 clip-path: polygon(50% 25%, 75% 75%, 25% 75%);

将裁剪与 CSS 过渡结合

clip-path 制作动画可以像使用 CSS 过渡将属性值从一个形状更改为另一个形状一样简单,这可以通过在 JavaScript 中更改类或交互式状态更改(如 :hover)来触发。

.box {
  clip-path: circle(75%);
  transition: clip-path 1s;
}

.box:hover {
  clip-path: circle(25%);
}

查看 CodePen 上的
带过渡的 clip-path
,作者:Geoff Graham (@geoffgraham)
CodePen 上。

我们还可以使用 CSS 动画

@keyframes circle {
  0% { clip-path: circle(75%); }
  100% { clip-path: circle(25%); }
}

查看 CodePen 上的
带 CSS 动画的 clip-path
,作者:Geoff Graham (@geoffgraham)
CodePen 上。

在为 clip-path 制作动画时需要考虑的一些事项

  • 它只影响渲染的内容,不会更改元素相对于周围元素的框大小。 例如,一个浮动框,其文本在周围流动,即使应用了非常小的百分比 clip-path,它仍然会占用相同的空间。
  • 任何超出元素框大小的 CSS 属性都可能会被裁剪。 例如,所有四边都为 0% 的 inset 会在元素的边缘进行裁剪,这将移除 box-shadow,并且需要使用负百分比才能看到 box-shadow。 不过,这本身可能会产生有趣的效果!

好的,让我们开始一些简单的动画。

比较简单的形状

我创建了一个演示,您可以在其中看到每个形状的实际效果,以及一些描述正在发生的事情的解释。

查看 CodePen 上的
Clip-Path 动画:简单形状
,作者:Travis Almand (@talmand)
CodePen 上。

演示使用 Vue 来实现功能,但 CSS 可以轻松地转移到任何其他类型的项目中。

我们可以将它们进一步分解,以掌握每个形状的值以及更改它们如何影响移动。

圆形

clip-path: circle(<length|percentage> at <position>);

圆形接受两个可以进行动画的属性

  1. 形状半径:可以是长度或百分比
  2. 位置:可以在 xy 轴上是长度或百分比
.circle-enter-active { animation: 1s circle reverse; }
.circle-leave-active { animation: 1s circle; }

@keyframes circle {
  0% { clip-path: circle(75%); }
  100% { clip-path: circle(0%); }
}

在离开过渡中,圆形形状从初始的 75% 半径(刚好足以让元素完全出现)缩小到 0% 进行调整大小。 由于未设置位置,圆形在垂直和水平方向上默认为元素的中心。 进入过渡通过动画属性中的“reverse”关键字反向播放动画。

椭圆形

clip-path: ellipse(<length|percentage>{2} at <position>);

椭圆形接受三个可以进行动画的属性

  1. 形状半径:可以在水平轴上是长度或百分比
  2. 形状半径:可以在垂直轴上是长度或百分比
  3. 位置:可以在 xy 轴上是长度或百分比
.ellipse-enter-active { animation: 1s ellipse reverse; }
.ellipse-leave-active { animation: 1s ellipse; }

@keyframes ellipse {
  0% { clip-path: ellipse(80% 80%); }
  100% { clip-path: ellipse(0% 20%); }
}

在离开过渡中,椭圆形形状从初始的 80% x 80%(使其成为比框更大的圆形)缩小到 0% x 20% 进行调整大小。 由于未设置位置,椭圆形在垂直和水平方向上默认为框的中心。 进入过渡通过动画属性中的“reverse”关键字反向播放动画。

效果是一个收缩的圆形,它变为一个比宽度高的收缩椭圆,擦除第一个元素。 然后元素切换,第二个元素出现在正在增大的椭圆形内。

内嵌

clip-path: inset(<length|percentage>{1,4} round <border-radius>{1,4});

内嵌形状最多有五个可以进行动画的属性。 前四个表示形状的每个边缘,它们的行为类似于边距或填充。 第一个属性是必需的,而接下来的三个是可选的,具体取决于所需的形状。

  1. 长度/百分比:可以表示所有四边、上/下边或上边
  2. 长度/百分比:可以表示左/右边或右边
  3. 长度/百分比:表示下边
  4. 长度/百分比:表示左边
  5. 边框半径:在值之前需要“round”关键字

需要注意的是,使用的值与典型的 CSS 用法相反。 用零定义边缘意味着没有任何变化,形状被向外推到元素的一侧。 随着数字的增加,例如增加到 10%,形状的边缘被向内推开,远离元素的一侧。

.inset-enter-active { animation: 1s inset reverse; }
.inset-leave-active { animation: 1s inset; }

@keyframes inset {
  0% { clip-path: inset(0% round 0%); }
  100% { clip-path: inset(50% round 50%); }
}

在离开过渡中,内嵌形状从一个全尺寸正方形缩小到一个圆形,这是由于圆角从 0% 更改为 50%。 如果没有 round 值,它将显示为一个收缩的正方形。 进入过渡通过动画属性中的“reverse”关键字反向播放动画。

效果是一个收缩的正方形,它变为一个收缩的圆形,擦除第一个元素。 元素切换后,第二个元素出现在正在增大的圆形内,该圆形变为一个增大的正方形。

多边形

clip-path: polygon(<length|percentage>);

在属性方面,多边形形状有点特殊。 每个属性表示形状的顶点,并且至少需要三个顶点。 除必需的三个顶点以外的顶点数仅受所需形状的要求限制。 对于动画的每个关键帧,或过渡中的两个步骤,顶点数必须始终匹配,才能实现平滑的动画。 顶点数的变化可以进行动画,但会导致每个关键帧出现弹出或弹出效果。

.polygon-enter-active { animation: 1s polygon reverse; }
.polygon-leave-active { animation: 1s polygon; }

@keyframes polygon {
  0% { clip-path: polygon(0 0, 50% 0, 100% 0, 100% 50%, 100% 100%, 50% 100%, 0 100%, 0 50%); }
  100% { clip-path:  polygon(50% 50%, 50% 25%, 50% 50%, 75% 50%, 50% 50%, 50% 75%, 50% 50%, 25% 50%); }
}

多边形形状中的八个顶点形成了一个正方形,在四个角和所有四边的中点都有一个顶点。 在离开过渡中,形状的角向内动画到中心,而边的中点向内动画到中心的一半。 进入过渡通过动画属性中的“reverse”关键字反向播放动画。

效果是一个向内折叠成一个加号形状的正方形,它擦除元素。 然后元素切换,第二个元素出现在一个正在增大的加号形状内,该形状扩展成一个正方形。

让我们来学习一些简单的运动

好的,现在我们已经完成了基础知识,让我们来提升一下难度。本演示展示了在 `clip-path` 动画中实现运动的不同方法。圆形和椭圆形可以通过改变形状的位置来轻松地实现运动动画。内嵌形状和多边形形状可以通过动画的方式,使元素看起来像是根据位置移动的。

查看 CodePen 上的演示:
动画剪裁路径:简单运动
,作者 Travis Almand (@talmand)
CodePen 上。

让我们像之前一样,逐个分析这些动画。

向下滑动

向下滑动动画包含两个使用内嵌形状的不同动画。第一个动画是退出动画,它将内嵌形状的顶边值从 0% 动画到 100%,使整个正方形看起来像是向下滑动到视野之外。第二个动画是进入动画,它将底边值设置为 100%,然后将其动画到 0%,使整个正方形看起来像是从视野之外向下滑动到视野之中。

.down-enter-active { animation: 1s down-enter; }
.down-leave-active { animation: 1s down-leave; }

@keyframes down-enter {
  0% { clip-path: inset(0 0 100% 0); }
  100% { clip-path: inset(0); }
}

@keyframes down-leave {
  0% { clip-path: inset(0); }
  100% { clip-path: inset(100% 0 0 0); }
}

正如你所看到的,内嵌路径中定义的边数不需要匹配。当形状需要成为完整的正方形时,只需要一个零即可。即使定义的边数增加到四个,它也可以动画到新的状态。

框擦除

框擦除动画包含两个动画,同样使用内嵌形状。第一个动画是退出动画,它将整个正方形动画成一个位于元素左侧的半尺寸正方形。然后,这个小正方形向右滑动到视野之外。第二个动画是进入动画,它将一个类似的半尺寸正方形从左侧动画到视野之中,一直到元素的右侧。然后它向外扩展以显示整个元素。

.box-wipe-enter-active { animation: 1s box-wipe-enter; }
.box-wipe-leave-active { animation: 1s box-wipe-leave; }

@keyframes box-wipe-enter {
  0% { clip-path: inset(25% 100% 25% -50%); }
  50% { clip-path: inset(25% 0% 25% 50%); }
  100% { clip-path: inset(0); }
}

@keyframes box-wipe-leave {
  0% { clip-path: inset(0); }
  50% { clip-path: inset(25% 50% 25% 0%); }
  100% { clip-path: inset(25% -50% 25% 100%); }
}

当显示完整元素时,内嵌形状为零。50% 的关键帧定义了一个半尺寸正方形,位于左侧或右侧。两个值分别表示左右边缘,它们被交换了。然后,正方形移动到对侧。当一侧被推到 100% 时,另一侧必须移动到 -50% 以保持形状。如果它动画到零而不是 -50%,那么正方形在动画时会缩小而不是移出视野。

旋转

旋转动画是一个包含五个关键帧的多边形动画。初始关键帧定义了一个包含四个顶点、显示完整元素的多边形。然后,下一个关键帧更改每个顶点的 `x` 和 `y` 坐标,使其向内移动并靠近下一个顶点,以顺时针方向移动。当所有四个顶点都完成过渡后,正方形看起来像是缩小并旋转了四分之一圈。后续的关键帧执行相同的操作,直到正方形缩小到元素的中心为止。退出动画正常播放动画,而进入动画则反向播放动画。

.rotate-enter-active { animation: 1s rotate reverse; }
.rotate-leave-active { animation: 1s rotate; }

@keyframes rotate {
  0% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%); }
  25% { clip-path: polygon(87.5% 12.5%, 87.5% 87.5%, 12.5% 87.5%, 12.5% 12.5%); }
  50% { clip-path: polygon(75% 75%, 25% 75%, 25% 25%, 75% 25%); }
  75% { clip-path: polygon(37.5% 62.5%, 37.5% 37.5%, 62.5% 37.5%, 62.5% 62.5%); }
  100% { clip-path: polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%); }
}

一旦设置了多边形的顶点,就可以将其动画到任何其他位置,只要每个关键帧都有相同数量的顶点即可。这可以通过仔细规划,实现许多有趣的效果。

聚光灯

聚光灯动画是一个包含五个关键帧的圆形动画。初始关键帧定义了一个位于中心、尺寸为完整的圆形,以显示完整元素。下一个关键帧将圆形缩小到 20%。每个后续的关键帧将圆形的位置值动画到元素上的不同点,直到它移出视野左侧。退出动画正常播放动画,而进入动画则反向播放动画。

.spotlight-enter-active { animation: 2s spotlight reverse; }
.spotlight-leave-active { animation: 2s spotlight; }

@keyframes spotlight {
  0% { clip-path: circle(100% at 50% 50%); }
  25% { clip-path: circle(20% at 50% 50%); }
  50% { clip-path: circle(20% at 12% 84%); }
  75% { clip-path: circle(20% at 93% 51%); }
  100% { clip-path: circle(20% at -30% 20%); }
}

乍一看,这个动画可能看起来很复杂,但实际上只需要在每个关键帧中进行简单的更改即可。

更具挑战性的内容

就像形状和简单运动示例一样,我制作了一个包含更复杂动画的演示。我们也会逐个分析这些动画。

查看 CodePen 上的演示:
动画剪裁路径:复杂形状
,作者 Travis Almand (@talmand)
CodePen 上。

所有这些示例都大量使用多边形形状。它们利用了诸如堆叠顶点以使元素看起来像是“焊接”在一起,以及重新定位顶点以实现运动的功能。

查看 Ana Tudor 的文章:“使用剪裁路径剪切元素的内部部分”,文章中包含更深入的示例,使用多边形形状创建复杂形状。

箭头

箭头动画由两个动画组成,每个动画包含三个关键帧。退出动画从一个完整的正方形开始,包含六个顶点;四个角加上左右两侧的两个顶点。第二个关键帧将三个顶点动画到适当的位置,将正方形变成一个箭头。第三个关键帧将顶点移出视野右侧。元素切换后,进入动画从同一个箭头形状开始,但它位于左侧视野之外。第二个关键帧将箭头移动到视野之中,然后第三个关键帧恢复完整的正方形。

.chevron-enter-active { animation: 1s chevron-enter; }
.chevron-leave-active { animation: 1s chevron-leave; }

@keyframes chevron-enter {
  0% { clip-path: polygon(-25% 0%, 0% 50%, -25% 100%, -100% 100%, -75% 50%, -100% 0%); }
  75% { clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 25% 50%, 0% 0%); }
  100% { clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 0% 100%, 0% 50%, 0% 0%); }
}

@keyframes chevron-leave {
  0% { clip-path: polygon(100% 0%, 100% 50%, 100% 100%, 0% 100%, 0% 50%, 0% 0%); }
  25% { clip-path: polygon(75% 0%, 100% 50%, 75% 100%, 0% 100%, 25% 50%, 0% 0%); }
  100% { clip-path: polygon(175% 0%, 200% 50%, 175% 100%, 100% 100%, 125% 50%, 100% 0%) }
}

螺旋

螺旋动画是多边形形状中复杂顶点序列的一个强有力示例。多边形被创建为一个形状,该形状从元素的左上角以顺时针方向螺旋向内。由于顶点创建的线相互堆叠,因此它们看起来像是单个正方形。在动画的八个关键帧中,顶点被移动到相邻顶点之上。这使得形状看起来像是以逆时针方向从左上角展开,在退出动画时擦除元素。进入动画则反向播放动画。

.spiral-enter-active { animation: 1s spiral reverse; }
.spiral-leave-active { animation: 1s spiral; }

@keyframes spiral {  
  0% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0% 25%, 75% 25%, 75% 75%, 25% 75%, 25% 50%, 50% 50%, 25% 50%, 25% 75%, 75% 75%, 75% 25%, 0% 25%); }
  14.25% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0% 25%, 75% 25%, 75% 75%, 50% 75%, 50% 50%, 50% 50%, 25% 50%, 25% 75%, 75% 75%, 75% 25%, 0% 25%); }
  28.5% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0% 25%, 75% 25%, 75% 50%, 50% 50%, 50% 50%, 50% 50%, 25% 50%, 25% 75%, 75% 75%, 75% 25%, 0% 25%); }
  42.75% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0% 25%, 25% 25%, 25% 50%, 25% 50%, 25% 50%, 25% 50%, 25% 50%, 25% 75%, 75% 75%, 75% 25%, 0% 25%); }
  57% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%, 0% 75%, 25% 75%, 25% 75%, 25% 75%, 25% 75%, 25% 75%, 25% 75%, 25% 75%, 75% 75%, 75% 25%, 0% 25%); }
  71.25% { clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 75% 100%, 75% 75%, 75% 75%, 75% 75%, 75% 75%, 75% 75%, 75% 75%, 75% 75%, 75% 75%, 75% 75%, 75% 25%, 0% 25%); }
  85.5% { clip-path: polygon(0% 0%, 100% 0%, 100% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 75% 25%, 0% 25%); }
  100% {clip-path: polygon(0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 0%, 0% 25%, 0% 25%, 0% 25%, 0% 25%, 0% 25%, 0% 25%, 0% 25%); }
}

插槽

插槽动画由一系列顶点组成,这些顶点以垂直插槽的模式排列,顶点相互堆叠形成一个完整的正方形。总体思路是,形状从左上角开始,下一个顶点位于右侧 14%。下一个顶点位于完全相同的位置。然后,下一个顶点位于右侧再 14% 的位置,依此类推,直到到达右上角。这将在形状的顶部创建一系列水平对齐的“部分”。第二个关键帧将所有偶数部分动画到元素的底部。这使得看起来像是垂直插槽擦除了其部分的元素。第三个关键帧将顶部的剩余部分移动到底部。总体而言,退出动画以垂直插槽擦除一半元素,然后擦除另一半。进入动画反向播放动画。

.slots-enter-active { animation: 1s slots reverse; }
.slots-leave-active { animation: 1s slots; }

@keyframes slots {
  0% {
    clip-path: polygon(0% 0%, 14% 0%, 14% 0%, 28% 0%, 28% 0%, 42% 0%, 42% 0%, 56% 0%, 56% 0%, 70% 0%, 70% 0%, 84% 0%, 84% 0%, 100% 0, 100% 100%, 0% 100%);
  }
  50% {
    clip-path: polygon(0% 0%, 14% 0%, 14% 100%, 28% 100%, 28% 0%, 42% 0%, 42% 100%, 56% 100%, 56% 0%, 70% 0%, 70% 100%, 84% 100%, 84% 0%, 100% 0, 100% 100%, 0% 100%);
  }
  100% {
    clip-path: polygon(0% 100%, 14% 100%, 14% 100%, 28% 100%, 28% 100%, 42% 100%, 42% 100%, 56% 100%, 56% 100%, 70% 100%, 70% 100%, 84% 100%, 84% 100%, 100% 100%, 100% 100%, 0% 100%);
  }
}

百叶窗

百叶窗过渡与上面的插槽过渡非常相似。它不像在顶部创建部分,而是创建垂直部分,这些部分彼此对齐以创建整个正方形。从左上角开始,第二个顶点位于顶部,向右 20%。下一个顶点在水平方向上位于相同位置,但在元素的底部。之后,下一个顶点位于相同位置,下一个顶点位于顶部,位于两个步骤之前的顶点之上。在元素右侧到达之前,此操作会重复多次。如果形状的线可见,那么它将显示为一系列垂直部分,水平排列在元素上。在动画期间,每个部分的左侧移到右侧的顶部。这会产生擦除效果,看起来像是窗户的垂直百叶窗。进入过渡以相反方式播放动画。

.shutters-enter-active { animation: 1s shutters reverse; }
.shutters-leave-active { animation: 1s shutters; }

@keyframes shutters {
  0% {
    clip-path: polygon(0% 0%, 20% 0%, 20% 100%, 20% 100%, 20% 0%, 40% 0%, 40% 100%, 40% 100%, 40% 0%, 60% 0%, 60% 100%, 60% 100%, 60% 0%, 80% 0%, 80% 100%, 80% 100%, 80% 0%, 100% 0%, 100% 100%, 0% 100%);
  }
  100% {
    clip-path: polygon(20% 0%, 20% 0%, 20% 100%, 40% 100%, 40% 0%, 40% 0%, 40% 100%, 60% 100%, 60% 0%, 60% 0%, 60% 100%, 80% 100%, 80% 0%, 80% 0%, 80% 100%, 100% 100%, 100% 0%, 100% 0%, 100% 100%, 20% 100%);
  }
}

星形

星形过渡利用了clip-path在定义形状的线重叠和交叉时如何渲染正空间和负空间。形状从一个具有八个顶点的正方形开始;每个角一个,每条边一个。只有三个关键帧,但每个关键帧都有大量移动。离开过渡从正方形开始,然后将每条边上的顶点移动到相对的边。因此,顶部顶点移到底部,底部顶点移到顶部,左侧和右侧的顶点也进行相同的交换。这会产生交叉线,在正空间中形成星形。最后一个关键帧将每个角的顶点移到形状的中心,这使得星形向内坍塌,擦除元素。进入过渡以相反方式播放。

.star-enter-active { animation: 1s star reverse; }
.star-leave-active { animation: 1s star; }

@keyframes star {
  0% {
    clip-path: polygon(0% 0%, 50% 0%, 100% 0%, 100% 50%, 100% 100%, 50% 100%, 0% 100%, 0% 50%);
  }
  50% {
    clip-path: polygon(0% 0%, 50% 100%, 100% 0%, 0% 50%, 100% 100%, 50% 0%, 0% 100%, 100% 50%);
  }
  100% {
    clip-path: polygon(50% 50%, 50% 100%, 50% 50%, 0% 50%, 50% 50%, 50% 0%, 50% 50%, 100% 50%);
  }
}

路径形状

好的,我们已经看了很多使用clip-path形状函数的动画示例。我们还没有花时间研究的一个函数是path。它可能是其中最灵活的一个,因为我们可以用它绘制自定义形状,甚至绘制多个形状。Chris 之前已经编写,甚至讲解过它。

因此,虽然我也为这组示例创建了演示,但请注意clip-path路径是实验性技术。截至撰写本文时,它仅在 Firefox 63 或更高版本中可用,需要在about:config中启用layout.css.clip-path-path.enabled标志。

查看 CodePen 上的
Animating Clip-Path: Path Shapes
,作者是 Travis Almand (@talmand)
CodePen 上。

此演示展示了路径的几种用途,这些路径被动画化以进行过渡。这些路径与SVG中发现的路径类型相同,可以从路径属性中提取出来,并在元素上的clip-path CSS 属性中使用。演示中的每条路径实际上都来自我手动为动画的每个关键帧制作的 SVG。就像使用多边形形状进行动画一样,需要仔细计划,因为路径中的顶点数量不能改变,只能被操纵。

使用路径的优点是可以包含路径内的多个形状,每个形状分别进行动画化,以对正空间和负空间进行微调控制。另一个有趣的方面是路径支持贝塞尔曲线。创建顶点类似于多边形形状,但多边形不支持贝塞尔曲线。此功能的一个额外好处是,即使曲线也可以进行动画化。

也就是说,缺点是必须针对元素的大小专门构建路径。这是因为没有百分比定位,就像我们在其他clip-path形状中一样。因此,本文的所有演示都使用 200px 正方形的元素,而此特定演示中的路径是为该大小构建的。任何其他大小或尺寸都会导致不同的结果。

好了,别再说了。让我们看看示例,因为它们非常棒。

虹膜

虹膜过渡由四个小形状组成,它们组合在一起形成一个完整的较大形状,该形状以虹膜图案分离,就像科幻电影中的门一样。每个形状的顶点都在远离中心的相反方向上移动并略微旋转,以便从元素的各个侧面移开。这仅使用两个关键帧完成。离开过渡使形状移出视野,而进入过渡则反转效果。路径的格式使路径中的每个形状都很明显。每条以“M”开头的线都是路径中的一个新形状。

.iris-enter-active { animation: 1s iris reverse; }
.iris-leave-active { animation: 1s iris; }

@keyframes iris {
  0% {
    clip-path: path('
      M103.13 100C103 32.96 135.29 -0.37 200 0L0 0C0.35 66.42 34.73 99.75 103.13 100Z
      M199.35 200C199.83 133.21 167.75 99.88 103.13 100C102.94 165.93 68.72 199.26 0.46 200L199.35 200Z
      M103.13 100C167.46 99.75 199.54 133.09 199.35 200L200 0C135.15 -0.86 102.86 32.47 103.13 100Z
      M0 200C68.63 200 103 166.67 103.13 100C34.36 100.12 -0.02 66.79 0 0L0 200Z
    ');
  }
  100% {
    clip-path: path('
      M60.85 2.56C108.17 -44.93 154.57 -45.66 200.06 0.35L58.64 -141.07C11.93 -93.85 12.67 -45.97 60.85 2.56Z
      M139.87 340.05C187.44 293.16 188.33 246.91 142.54 201.29C95.79 247.78 48.02 247.15 -0.77 199.41L139.87 340.05Z
      M201.68 61.75C247.35 107.07 246.46 153.32 199.01 200.5L340.89 59.54C295.65 13.07 249.25 13.81 201.68 61.75Z
      M-140.61 141.25C-92.08 189.78 -44.21 190.51 3.02 143.46C-45.69 94.92 -46.43 47.05 0.81 -0.17L-140.61 141.25Z
    ');
  }
}

熔化

熔化过渡包括进入和离开的两种不同的动画。在离开过渡中,路径是一个正方形,但顶部由几个贝塞尔曲线组成。首先,这些曲线被设置为完全平坦,然后向下动画,停在形状底部的下方。当这些曲线向下移动时,它们以不同的方式进行动画化,因此每条曲线与其他曲线调整的方式不同。这使得元素看起来像是从底部下方熔化出视野。

进入过渡与之类似,只是曲线位于正方形的底部。曲线从顶部开始,完全平坦。然后它们以相同的曲线调整向下动画。这使得第二个元素看起来像是熔化到视图底部。

.melt-enter-active { animation: 2s melt-enter; }
.melt-leave-active { animation: 2s melt-leave; }

@keyframes melt-enter {
  0% {
    clip-path: path('M0 -0.12C8.33 -8.46 16.67 -12.62 25 -12.62C37.5 -12.62 35.91 0.15 50 -0.12C64.09 -0.4 62.5 -34.5 75 -34.5C87.5 -34.5 87.17 -4.45 100 -0.12C112.83 4.2 112.71 -17.95 125 -18.28C137.29 -18.62 137.76 1.54 150.48 -0.12C163.19 -1.79 162.16 -25.12 174.54 -25.12C182.79 -25.12 191.28 -16.79 200 -0.12L200 -34.37L0 -34.37L0 -0.12Z');
  }
  100% {
    clip-path: path('M0 199.88C8.33 270.71 16.67 306.13 25 306.13C37.5 306.13 35.91 231.4 50 231.13C64.09 230.85 62.5 284.25 75 284.25C87.5 284.25 87.17 208.05 100 212.38C112.83 216.7 112.71 300.8 125 300.47C137.29 300.13 137.76 239.04 150.48 237.38C163.19 235.71 162.16 293.63 174.54 293.63C182.79 293.63 191.28 262.38 200 199.88L200 0.13L0 0.13L0 199.88Z');
  }
}

@keyframes melt-leave {
  0% {
    clip-path: path('M0 0C8.33 -8.33 16.67 -12.5 25 -12.5C37.5 -12.5 36.57 -0.27 50 0C63.43 0.27 62.5 -34.37 75 -34.37C87.5 -34.37 87.5 -4.01 100 0C112.5 4.01 112.38 -18.34 125 -18.34C137.62 -18.34 138.09 1.66 150.48 0C162.86 -1.66 162.16 -25 174.54 -25C182.79 -25 191.28 -16.67 200 0L200 200L0 200L0 0Z');
  }
  100% {
    clip-path: path('M0 200C8.33 270.83 16.67 306.25 25 306.25C37.5 306.25 36.57 230.98 50 231.25C63.43 231.52 62.5 284.38 75 284.38C87.5 284.38 87.5 208.49 100 212.5C112.5 216.51 112.38 300.41 125 300.41C137.62 300.41 138.09 239.16 150.48 237.5C162.86 235.84 162.16 293.75 174.54 293.75C182.79 293.75 191.28 262.5 200 200L200 200L0 200L0 200Z');
  }
}

门过渡类似于我们首先看到的虹膜过渡——它是一种“门”效果,形状彼此独立移动。路径由四个形状组成:两个是位于顶部和底部的半圆,另外两个将左侧的剩余正空间分开。这表明,路径中的每个形状不仅可以彼此独立地进行动画化,而且还可以是完全不同的形状。

在离开过渡中,每个形状都从中心移开,从它自己的侧面移出视野。顶部半圆向上移动,留下一个洞,底部半圆也这样做。然后,左右两侧在另一个关键帧中滑动离开。然后,进入过渡简单地反转动画。

.door-enter-active { animation: 1s door reverse; }
.door-leave-active { animation: 1s door; }

@keyframes door {
  0% {
    clip-path: path('
      M0 0C16.03 0.05 32.7 0.05 50 0C50.05 27.36 74.37 50.01 100 50C99.96 89.53 100.08 136.71 100 150C70.48 149.9 50.24 175.5 50 200C31.56 199.95 14.89 199.95 0 200L0 0Z
      M200 0C183.46 -0.08 166.79 -0.08 150 0C149.95 21.45 133.25 49.82 100 50C100.04 89.53 99.92 136.71 100 150C130.29 150.29 149.95 175.69 150 200C167.94 199.7 184.6 199.7 200 200L200 0Z
      M100 50C130.83 49.81 149.67 24.31 150 0C127.86 0.07 66.69 0.07 50 0C50.26 23.17 69.36 49.81 100 50Z
      M100 150C130.83 150.19 149.67 175.69 150 200C127.86 199.93 66.69 199.93 50 200C50.26 176.83 69.36 150.19 100 150Z
    ');
  }
  50% {
    clip-path: path('
      M0 0C16.03 0.05 32.7 0.05 50 0C50.05 27.36 74.37 50.01 100 50C99.96 89.53 100.08 136.71 100 150C70.48 149.9 50.24 175.5 50 200C31.56 199.95 14.89 199.95 0 200L0 0Z
      M200 0C183.46 -0.08 166.79 -0.08 150 0C149.95 21.45 133.25 49.82 100 50C100.04 89.53 99.92 136.71 100 150C130.29 150.29 149.95 175.69 150 200C167.94 199.7 184.6 199.7 200 200L200 0Z
      M100 -6.25C130.83 -6.44 149.67 -31.94 150 -56.25C127.86 -56.18 66.69 -56.18 50 -56.25C50.26 -33.08 69.36 -6.44 100 -6.25Z
      M100 206.25C130.83 206.44 149.67 231.94 150 256.25C127.86 256.18 66.69 256.18 50 256.25C50.26 233.08 69.36 206.44 100 206.25Z
    ');
  }
  100% {
    clip-path: path('
      M-106.25 0C-90.22 0.05 -73.55 0.05 -56.25 0C-56.2 27.36 -31.88 50.01 -6.25 50C-6.29 89.53 -6.17 136.71 -6.25 150C-35.77 149.9 -56.01 175.5 -56.25 200C-74.69 199.95 -91.36 199.95 -106.25 200L-106.25 0Z
      M306.25 0C289.71 -0.08 273.04 -0.08 256.25 0C256.2 21.45 239.5 49.82 206.25 50C206.29 89.53 206.17 136.71 206.25 150C236.54 150.29 256.2 175.69 256.25 200C274.19 199.7 290.85 199.7 306.25 200L306.25 0Z
      M100 -6.25C130.83 -6.44 149.67 -31.94 150 -56.25C127.86 -56.18 66.69 -56.18 50 -56.25C50.26 -33.08 69.36 -6.44 100 -6.25Z
      M100 206.25C130.83 206.44 149.67 231.94 150 256.25C127.86 256.18 66.69 256.18 50 256.25C50.26 233.08 69.36 206.44 100 206.25Z
    ');
  }
}

X-Plus

此过渡与本文中的大多数演示不同。这是因为其他演示展示了对过渡的clip-path“正”空间进行动画化。事实证明,使用传统的 clip-path 形状对“负”空间进行动画化可能很困难。可以使用多边形形状来完成,但这需要仔细放置顶点以创建负空间,并根据需要对其进行动画化。此演示利用了路径中的两个形状;有一个形状是一个巨大的正方形,围绕着元素的空间,另一个形状位于此正方形的中心。中心形状(在本例中为x+)会排除或“雕刻”出外部形状中的负空间。然后对中心形状的顶点进行动画化,以便只对负空间进行动画化。

离开动画从中心形状开始,中心形状是一个很小的“x”,它会逐渐变大,直到元素被擦除。在进入动画中,中心形状是一个“+”,它已经比元素更大,然后缩小到无。

.x-plus-enter-active { animation: 1s x-plus-enter; }
.x-plus-leave-active { animation: 1s x-plus-leave; }

@keyframes x-plus-enter {
  0% {
    clip-path: path('M-400 600L-400 -400L600 -400L600 600L-400 600ZM0.01 -0.02L-200 -0.02L-200 199.98L0.01 199.98L0.01 400L200.01 400L200.01 199.98L400 199.98L400 -0.02L200.01 -0.02L200.01 -200L0.01 -200L0.01 -0.02Z');
  }
  100% {
    clip-path: path('M-400 600L-400 -400L600 -400L600 600L-400 600ZM98.33 98.33L95 98.33L95 101.67L98.33 101.67L98.33 105L101.67 105L101.67 101.67L105 101.67L105 98.33L101.67 98.33L101.67 95L98.33 95L98.33 98.33Z');
  }
}

@keyframes x-plus-leave {
  0% {
    clip-path: path('M-400 600L-400 -400L600 -400L600 600L-400 600ZM96.79 95L95 96.79L98.2 100L95 103.2L96.79 105L100 101.79L103.2 105L105 103.2L101.79 100L105 96.79L103.2 95L100 98.2L96.79 95Z');
  }
  100% {
    clip-path: path('M-400 600L-400 -400L600 -400L600 600L-400 600ZM-92.31 -200L-200 -92.31L-7.69 100L-200 292.31L-92.31 400L100 207.69L292.31 400L400 292.31L207.69 100L400 -92.31L292.31 -200L100 -7.69L-92.31 -200Z');
  }
}

水滴

水滴过渡利用了在同一路径中具有多个形状的能力。路径在元素区域内策略性地放置了十个圆圈。它们从很小且不可见开始,然后随着时间的推移动画化到更大的尺寸。动画中有十个关键帧,每个关键帧都调整圆圈的大小,同时保持之前调整大小的任何圆圈的状态。这使得圆圈在动画期间一个接一个地弹出或消失。

离开过渡使圆圈逐个缩小出视野,负空间扩大以擦除元素。进入过渡以相反方式播放动画,使圆圈变大,正空间扩大以显示新元素。

用于 drops 过渡的 CSS 比较大,所以请查看 CodePen 演示的 CSS 部分,从 .drops-enter-active 选择器开始。

数字

此过渡与上面的 x-plus 过渡类似 - 它在更大的正形内使用负形进行动画。在此演示中,动画形状在元素被擦除或显示之前会依次经过数字 1、2 和 3。数字形状是通过将每个数字的顶点操作成下一个数字的形状来创建的。因此,每个数字形状都具有相同数量的顶点和曲线,它们可以从一个到下一个正确地进行动画。

离开过渡从形状位于中心开始,但被设置为不可见。然后它动画到第一个数字的形状。下一个关键帧动画到下一个数字,依此类推,然后反向播放。

用于此的 CSS 与上一个一样庞大,所以请查看 CodePen 演示的 CSS 部分,从 .numbers-enter-active 选择器开始。


希望本文能让你对如何使用 clip-path 创建灵活且强大的动画有一个很好的了解,这些动画既可以是简单的,也可以是复杂的。动画可以为设计增添一抹亮色,甚至可以在从一种状态切换到另一种状态时提供上下文。同时,请记住,要考虑到那些可能更喜欢限制动画或移动量的人,例如通过 设置减少运动的首选项