使用 CSS 剪切路径创建交互式效果

Avatar of Mikael Ainalem
Mikael Ainalem

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 $200 免费信用额度!

你还记得小时候从杂志上剪下图片吗?你会把它们粘在纸上,创作自己的拼贴画吗?这篇文章是关于使用 CSS 属性 clip-path 在网络上剪切图片的。我们将讨论如何剪切以及如何使用这些剪切的部分来创建一些有趣的效果,并将这些剪切的部分与原始图片结合在一起。

我将使用以下照片作为示例。这朵花在照片中很突出,它是剪切和创建周围效果的自然焦点。

Hand holding a flower
图片由 Unsplash 提供。作者:Hermes Rivera

创建 SVG

首先,我们将创建一个新的 SVG 文件,并将示例图片导入其中。您将需要具有矢量功能的图像编辑软件来进行剪切。我使用的是 Inkscape,一个免费的开源编辑器,但是您可以使用其他应用程序(如 Adobe Illustrator 或在线编辑器,如 Vectr)来应用这篇文章中介绍的相同方法。

让我们从在图像编辑器中创建一个新的 100px 正方形 SVG 文档开始。使用 100px 正方形很重要,因为剪切路径以长度百分比的形式出现。选择 0-100 范围将允许从像素到百分比的无缝转换。

在继续之前,我发现非常有价值的一件事是检查编辑器输出的 SVG 代码。获取该输出取决于应用程序。例如,在 Illustrator 中,仅 两种方法。查看标记使我们能够深入了解编辑器在幕后所做的工作,因为并非所有应用程序都以 相同的方式 导出 SVG。查看代码将提高您对标记的理解。这是一件双赢的事。

SVG 输出应该给我们类似这样的东西

<svg … width="100px" height="100px" viewBox="0 0 100 100" …>
	...
</svg>

上面更重要的部分之一是 viewBox 属性,因为它表示 SVG 文档的内部坐标系。这里有一篇关于 其工作原理 的详细解释。在上面,我们可以看到文档具有正确的比例,其中 widthheightviewBox 都从 0 到 100 跨越。

接下来是导入图片。在这里,我们需要将图片调整大小到 100px 正方形,并将其放置在原点 (0, 0)。这样做可能会破坏图片的纵横比,除非您的图片已经是正方形比例。我们的示例图片不是。在之后应用 clip-path 时,这将不是问题。

Rescaling the image
图片临时重新缩放以满足新的正方形比例。

再次查看生成的代码,现在我们应该看到 SVG 文档中的 <image> 标记。注意 preserveAspectRatio 设置为 none。这告诉我们图片的原始尺寸被忽略了。

<svg … width="100px" height="100px" viewBox=“0 0 100 100”>
	...
  <image … y="0" x="0" xlink:href=".../image-file-name.jpg" preserveAspectRatio="none" height="100"
width="100" … />
	...
</svg>

遮罩图片文件

现在进行实际的图片剪切。

剪切图片的概念称为遮罩。如果您不熟悉遮罩,它本质上是在图片区域周围使用钢笔工具绘制一个封闭的形状。您不需要精通矢量编辑器来完成此操作。它不需要任何特殊的艺术技能,并且可以通过几个基本步骤完成。

数字图片遮罩非常类似于从真实杂志上剪切图片。在矢量编辑器中创建的路径与使用剪刀遵循的路径相同。选择钢笔工具,并开始绘制您要剪切的图片部分的轮廓。在本例中,它是我们之前指出的花卉焦点。沿途创建任意数量的点来塑造遮罩。最后一步一定要闭合路径。

在剪切时只使用尖点节点很重要,因为在撰写本文时,clip-path 不支持复杂形状,例如贝塞尔曲线。它只支持简单的形状,例如多边形、圆形和椭圆形。

如果我们现在查看 SVG 代码,输出将包含一个带有您绘制的形状的所有坐标的路径。这是一个路径输出的简化示例

	...
	<path
		d="m 52.843605,79.860084 -0.69448,1.767767 -0.883884,0 -1.26269,-1.578364 -0.757615,0.06314 -1.388959,-2.714785 -0.12627,-2.967323 -1.704632,2.525381 -1.136422,-0.126269 -0.505076,-2.841054 -1.515229,1.325825 -1.325825,-0.126269 -0.252538,-1.578363 -0.947018,-0.126269 -0.252538,-0.315673 -0.947018,0.126269 -0.69448,-0.757614 0.126269,-1.641498 -0.441942,-0.252538 -0.189403,-2.588516 -0.505077,-0.06314 -1.010152,0.568211 -0.568211,-1.452094 0.441942,-2.399112 -1.325825,-0.126269 -0.378808,-1.262691 0.378808,-2.08344 0.883883,-1.641498 -1.010152,-1.26269 0.505076,-1.957171 -1.452094,-1.010152 -0.378808,-1.010153 1.136422,-2.209709 -2.209709,-0.378807 -0.441941,-1.704632 0.631345,-2.020305 1.704632,-1.38896 -1.578363,-1.452094 0.568211,-2.462247 0.820749,-0.441942 0.126269,-1.515229 0.757614,-1.073287 0.441942,-1.515228 -0.505076,-1.38896 0,-2.272843 0.505076,-1.010153 1.136422,-0.505076 1.325825,0 0.06313,-0.568211 -0.947018,-2.08344 0.378807,-0.631345 0,-0.441942 1.073288,-0.69448 1.073287,0 0.56821,0.315673 -0.189403,-2.525381 0.189403,-0.883884 0.378808,0.757615 0.06313,-0.883884 0.378807,-0.378807 0.189404,-0.378807 0.126269,-2.08344 0.315673,0.06314 0,-0.568211 0.378807,-0.06313 1.199556,0.568211 0.505076,0.69448 0.252538,-2.08344 0.631346,-0.505076 0.631345,-0.568211 0.441942,-0.505076 0.252538,0.505076 0,-0.883883 1.262691,0.315673 0.820749,-1.894036 1.325825,1.136421 1.073287,-1.452094 0.820749,0.189403 1.010152,1.515229 0.505077,0.757615 0.631345,-1.452095 0.820749,-0.56821 0.820749,0.505076 0.378807,0.631345 0.820749,-0.189403 0.820749,0.947018 0,0.252538 0.69448,-0.126269 0.378807,0.631345 0.820749,0 0.568211,1.515229 0.378807,1.325825 0.505076,-0.189404 0.252538,0.441942 0.378808,0.126269 0.441941,2.08344 0,0.568211 0.505077,-0.126269 0,0.883883 0.694479,-0.252538 0.505077,0.505076 0.252538,0.947018 0,0.883884 0.315673,0 0.378807,0.631345 0.441941,0.631345 0.06314,1.515229 -0.378807,1.957171 -0.441942,1.767767 2.904189,-1.136422 0.252538,0.631345 0.126269,2.209709 -0.883884,1.830902 1.38896,0.378807 1.010153,1.199556 -0.378808,1.641498 -0.947018,1.767767 -0.505076,0.378807 0.69448,1.767767 1.010153,1.26269 0.378807,1.38896 -0.378807,1.515229 -0.568211,0.315673 -0.505077,1.010152 -1.452094,0.883884 0.189404,1.325825 0.315672,0.883883 -0.378807,1.38896 -1.388959,1.073287 -0.505077,0.126269 0,0.505077 -0.189403,1.830901 -1.010153,0.631345 0.820749,2.209709 -0.631345,1.452094 -1.641498,-0.189403 0.126269,1.578363 -0.315673,1.641498 -1.073287,0.505076 -0.378807,0.315673 -0.378807,0.883883 -0.252538,1.010153 0.06313,2.714785 -0.631345,0.631345 -1.578364,-0.883883 -0.757614,-1.262691 -0.189404,2.462247 0.189404,2.083439 -0.252538,2.588516 -0.441942,1.894036 -0.631345,0.631346 -0.631345,-0.189404 -0.820749,-0.883883 z"
	/>
	...

以下是我剪切花朵和结果的视频。剪切大约花了 2 分钟,结果相当不错。

这是我的图片,遮罩的透明度略低,以显示最终剪切的形状

将 SVG 转换为 CSS 剪切路径

现在我们有了遮罩,让我们看看如何从 SVG 转换为 clip-path。这意味着转换路径描述符,或 SVG 代码中的 d 属性。

在研究如何进行转换之前,让我们谈谈使用剪切路径的原因。您可能会问,为什么要创建剪切路径?为什么不在矢量编辑器中遮罩图片并导出一个预剪切图片?这是可能的,并且使用图片比使用大量 CSS 代码要方便得多。但是,在我看来,使用剪切路径有两个主要好处:交互性和压缩。SVG 本质上是 DOM 中的代码,可以进行操作,并且其文件大小比具有相同形状的位图图片要小得多。

CSS 剪切路径的语法与 SVG 中的语法略有不同。对以逗号分隔,坐标以空格分隔。这与 SVG 描述符语法完全相反。为了使转换更加复杂,有些形状只使用绝对坐标。SVG 路径更加灵活,因为它们可以使用两种坐标系。

我创建了一个 简单的 Node 脚本 来转换 SVG 路径。它接受相对坐标的路径,并使用 CSS clip-path 输出相应的多边形。它使用正则表达式来解析 SVG 文件。您可以随意对其进行分叉并增强它。一个明显的补充是添加比例的规范化。添加规范化将消除在创建遮罩时只使用正方形图片的需要。

这是将剪切路径应用于花朵照片的结果

查看 Pen 剪切图片 by Mikael Ainalem (@ainalem) on CodePen.

使用 CSS 剪切路径的技巧

现在我们有了剪切的部分,让我们看看可以用它做什么。

叠加效果

一个很巧妙的技巧是将剪切的部分叠加在原始图片之上。以下是一个笔,说明了将剪切的部分叠加在原始图片之上的想法。它将让您了解定位和涉及的两个不同部分。拥有这两个不同的元素使我们能够分别对前景和背景应用不同的效果。

查看 Pen 剪切图片 #2 by Mikael Ainalem (@ainalem) on CodePen.

突出显示效果

突出显示图片上的部分不仅在视觉上吸引人。它还可以对您网站的用户体验产生真正的影响。想出一些有用的场景并不难,您可能希望在网页上突出显示图片的部分。在照片中突出显示标记的人可能是一个用例。另一个可能是突出显示产品展示中的产品的某些功能。第三种情况可能是地图的照片,您希望突出显示一些地方来进行一些故事讲述。在适当应用的情况下,突出显示或强调 UI 部分可以成为强大的 UX 模式。使用剪切路径是实现 UI 中突出显示的一种方式。

回到花卉照片,我们现在可以轻松地让花卉脱颖而出。实现这一点的一种方法是通过降低背景的透明度来降低花卉后面背景的色调

查看 Pen 剪切图片 #3 by Mikael Ainalem (@ainalem) on CodePen.

一个有趣的注意事项是浏览器将命中测试遮罩。因此,为了使其更具趣味性,我们可以当用户悬停在花朵上时触发突出显示效果。实现此目的的一种方法是添加 JavaScript 事件处理程序 (addEventListener) 并将其附加到遮罩元素。将这些处理程序设置为在诸如 mouseentermouseout 等事件上触发,会捕获用户悬停在花朵上的操作。我们甚至可以在背景元素上切换类来触发效果。CSS 透明度过渡本质上是必需的。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #4

没有什么可以阻止我们在同一张图像中多次重复使用上述技术。以下是一个在照片中突出显示多人的示例。在这种情况下,有多个叠加的剪切。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 clip-path 突出显示

淡入淡出和模糊效果

我们在过去一年中看到的效果是模糊背景。这是一种反向增强前景元素的方式。与其增强前景元素本身,不如通过模糊背景元素来创建相同的效果。这种增强前景元素的方式还有另一个令人愉快的副作用:您当前焦点中的元素保持不变。但同时,它也变得更加突出。

实现模糊效果的最简单方法是使用 CSS 滤镜模糊。以下代码笔使用与上一个示例相同的 JavaScript 回调方法来触发悬停时的效果。它不是淡化背景,而是使用 CSS 滤镜过渡将其模糊。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #9

但是,使用 CSS 滤镜的过渡在性能方面非常昂贵。这与用于创建模糊效果的 GPU 上运行的着色器有关。动画 CSS 模糊滤镜通常不是一个好主意。一个性能更好的选择是重复使用图像的预先过滤版本并使用交叉淡入淡出。换句话说,我们动画化重复背景图像的不透明度,而不是动画化模糊。以下是它的外观

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #10

轮廓

加强剪切元素的另一个选择是使用轮廓效果。重复使用蒙版是实现它的简单方法。如果我们将 SVG 插入两个主要元素之间并添加轻微的缩放比例(在这种情况下为 1.04),它将显示为轮廓。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #5

当然,我们也可以像在其他示例中那样在悬停时触发轮廓。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #6

蒙版的边缘有点粗糙,因为蒙版是二进制的。软化边缘的一个选择是添加 SVG 滤镜。以下是一个示例

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #8

剪切孔

如果您要剪切的部分有孔怎么办?如果它显示了您想要排除的背景部分怎么办?

例如,假设您想剪切一个甜甜圈。然后您想让蒙版排除中间的孔。那么如何剪切蒙版呢?clip-path 规范不允许使用多个多边形,除非我们使用 SVG。这意味着不可能一次创建多个形状。

好吧,创建这些孔的一种方法是使用非常细的连接器并将其绘制成一个形状。换句话说,我们可以从边缘进行非常细的切口并剪切掉孔。此代码笔说明了将这些连接器做得非常细时的外观。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #7

变形剪切路径

为了使突出显示效果更加生动,我们实际上可以变形 clip-path 本身。以下是在三张照片中动态突出显示蝴蝶的示例。突出显示在悬停时会在三个不同的剪切部分之间变形。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 剪切图像 #11

双重曝光效果

我们可以使用 clip-path 创建的另一个有趣的效果是双重曝光。这里有两张图像在同一个蒙版中混合在一起。

查看 CodePen 上 Mikael Ainalem(@ainalem)的 双重曝光

浏览器支持

那么,clip-path 能否在所有浏览器中使用呢?不幸的是,目前还不行!如果我们查看 caniuse 表格,在撰写本文时它看起来有点像交通信号灯。

此浏览器支持数据来自 Caniuse,其中包含更多详细信息。数字表示浏览器从该版本开始支持该功能。

台式机

ChromeFirefoxIEEdgeSafari
13054127TP

移动/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari
12712712718.0

总结

我希望您从本文中了解到一些关键要点

  • 使用剪切路径是使图像的一部分脱颖而出的方法之一
  • 将剪切部分叠加在原始图像之上,可以创建图像中不同类型的突出显示效果
  • 我们可以利用浏览器对蒙版的命中测试来在剪切部分上创建交互式效果
  • clip-path 属性为突出显示图像部分并围绕其创建效果的 UX 模式铺平了道路

致谢

  • Inkscape 用于矢量图像编辑
  • Unsplash 用于示例中使用的免版税图像
  • Github 用于转换脚本的存储库
  • npm 作为转换脚本的包管理器
  • caniuse 用于浏览器支持参考
  • CodePen 用于托管本文中使用的演示