Smashing Animations Part 2: How CSS Masking Can Add An Extra Dimension — Smashing Magazine
什么是遮罩?
一个简单的遮罩例子出现在《Disguise and Gals》以及无数其他卡通片的结尾。这里,一个动画渐晕逐渐隐藏了Yogi的更多脸部。遮罩后面的内容并没有被擦除;只是被隐藏了。
在CSS中,遮罩使用位图、矢量或渐变遮罩图像来控制可见性。当遮罩的填充像素覆盖一个元素时,其内容将可见。当它们透明时,内容将被隐藏,这很合理。填充像素可以是任何颜色,但我总是使用亮粉色,这样我就能清楚地知道哪些区域会可见。
clip-path的功能类似于遮罩,但使用路径创建硬边裁剪区域。如果你想要挑剔,遮罩和裁剪路径在技术上是不同的,但使用它们的目标通常是相同的。因此,在本文中,我将它们视为同一个洞穴的两个入口,并将使用其中任何一种称为“遮罩”。
在《Disguise and Gals》的这个序列中,其中一个抢劫犯匆忙将装有赃物的野餐篮带入Yogi的洞穴。遮罩定义了可见区域,创造了抢劫犯进入洞穴的错觉。
我如何选择何时使用clip-path,何时选择mask?我将在每个例子中解释我的理由。
当Mike Worth和我讨论合作时,我们知道我们既没有预算也没有时间为他的网站创建一个简短的动画卡通。然而,我们热衷于探索动画如何将原本是静态图像的内容变得生动。
Mike Worth的网站将于2025年6月上线,但您可以在CodePen上查看本文中的示例。
使用裁剪路径进行遮罩
在Mike的传记页面上,他的角色也进入了一个洞穴。我创建的SVG插图包含两个组,一个用于背景,另一个用于前景中的猩猩:
|
|
我定义了一个关键帧动画,通过改变其平移值,将角色从右侧2000px移动到帧中心的自然位置:
|
|
然后,我将该动画应用到前景组:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的关于页面(无clip-path)[forked] by Andy Clarke。
虽然50px的弹跳为他的移动增添了一丝真实感,但我不满意角色从视口边缘开始进入的方式。
我希望他在插图的边缘变得可见。由于洞穴墙壁的边缘是硬的,我选择了clip-path。
在CSS中有几种定义clip-path的方法。我可以使用像矩形这样的基本形状,其中前四个值指定其角位置。round关键字和随后的值定义任何圆角:
|
|
或者使用xywh(x, y, width, height)值,我觉得这样更容易阅读:
|
|
我可以使用圆形:
|
|
或椭圆:
|
|
我可以使用多边形形状:
|
|
甚至使用我在Sketch等图形应用中创建的路径的点:
|
|
最后——也是我在这个例子中的选择——我可能使用一个使用SVG文件中的路径定义的遮罩:
|
|
为了让角色从插图边缘可见,我添加了第二个SVG。为了防止浏览器显示它,将其尺寸设置为零:
|
|
这包含一个单独的SVG clipPath。通过将其放在defs元素中,这个路径不会被渲染,但它将可用于创建我的CSS clip-path:
|
|
我将clipPath URL应用到我的插图,现在Mike的吉祥物只有在他进入洞穴时才变得可见:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的关于页面(带clip-path)[forked] by Andy Clarke。
提示:实现该代码后,您会注意到在调整浏览器窗口大小时存在问题。虽然我的洞穴插图是灵活的,但clipPath保持固定宽度。
要使clipPath响应式,请在 opening tag 中添加 clipPathUnits=“objectBoundingBox”,然后将两个缩放值应用到 transform 属性。要计算这些值,首先将1除以SVG的宽度,然后除以其高度。我的SVG宽度是1400px,产生第一个缩放值0.0007142857143。
|
|
裁剪不规则形状
我经常需要更改或修改插图——可能是通过叠加颜色或应用混合模式——但我希望保留它们的整体形状。
虽然clipPath会给我想要的结果,但这些路径的复杂性和大小有时会对性能产生负面影响。那时我选择CSS遮罩,因为它的属性自2023年以来已经成为基线并且高度可用。
mask属性是一个简写,可以包括mask-clip、mask-mode、mask-origin、mask-position、mask-repeat、mask-size和mask-type的值。我发现最好单独学习这些属性,以更容易掌握遮罩的概念。
遮罩使用位图、矢量或渐变遮罩图像来控制可见性。同样,当遮罩的填充像素覆盖一个元素时,其内容将可见。当它们透明时,内容将被隐藏。当遮罩的部分是半透明时,部分内容将显示出来。我可以使用包含alpha通道的位图格式,例如PNG或WebP:
|
|
我可以使用矢量图形应用遮罩:
|
|
或者使用圆锥、线性或径向渐变生成图像:
|
|
…或者:
|
|
我可能对一个元素应用多个遮罩,并使用应该熟悉的语法混合几种图像类型:
|
|
mask与CSS背景共享相同的语法,这使得记住其属性更加容易。要应用background-image,添加其URL值:
|
|
要应用遮罩,将background-image属性替换为mask-image:
|
|
mask属性也与CSS背景共享相同的浏览器样式,因此默认情况下,遮罩将水平和垂直重复,除非我另有指定:
|
|
它将放置在左上角,除非我改变其位置:
|
|
另外,我可以像background-size一样指定mask-size:
|
|
最后,我可以定义遮罩开始的位置:
|
|
使用遮罩图像
Mike的FAQ页面包括一个他的英雄站在十字路口的动画插图。我的目标是将形状与其内容分开,允许我在英雄的旅程中更改插图。因此,我创建了一个可缩放的mask-image,定义了可见区域,并将其应用到figure元素:
|
|
为了确保遮罩与插图的尺寸匹配,我还将mask-size设置为始终覆盖其内容:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的FAQ(mask-image)[forked] by Andy Clarke。
虽然“X”从未标记地点,但Mike Worth的评论页面插图显示他的猩猩吉祥物正在研究他的宝藏地图。我想通过使用椭圆形将某人的注意力集中在图像的中心部分。
|
|
然而,clip-path的硬边并没有创造出我旨在实现的效果:
自己尝试一下: 参见CodePen上的Mike Worth的评论页面(椭圆)[forked] by Andy Clarke。
我尝试通过将高斯模糊滤镜与SVG中定义的遮罩结合使用,首先创建滤镜,然后将其应用到遮罩的椭圆:
|
|
虽然这实现了我要找的结果,但实现感觉过于复杂,毕竟只是一个简单的效果。到目前为止,最有效、优雅和响应式的实现使用了径向渐变,实现了我希望的效果,没有位图或矢量图像,只有一个CSS属性:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的评论页面(径向渐变遮罩)[forked] by Andy Clarke。
这种方法使我能够微调我的mask-image大小,甚至在有人与其内容交互时动画其颜色停止点、位置和大小。
分层多个遮罩
照明在Mike Worth的评论页面上尤其重要,他的猩猩英雄需要它来研究他的宝藏地图。像背景图像一样,我可以应用多个遮罩图像来创建我需要的照明。
我可以组合两个遮罩图像:一个圆形、半透明的径向渐变用于提供氛围,加上一个45度角的线性渐变用于光线。我将它们都应用到figure元素:
|
|
我分别定位了遮罩,将径向渐变大小设置为80%,线性渐变光线覆盖整个图像:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的评论页面(分层多个遮罩)[forked] by Andy Clarke。
但是,我需要更精确地控制光线的位置,以创造它们来自台灯的效果。因此,我用软边位图图像替换了线性渐变:
|
|
最后,为了增加一丝真实感,我添加了一个关键帧动画——改变mask-size并创造灯光明灭的效果——并将其应用到figure:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的评论页面(多个mask-images)[forked] by Andy Clarke。
动画遮罩
动画CSS遮罩创造了令人兴奋的揭示和场景之间的过渡,并帮助某人关注关键内容。它还可以将故事变得生动,使一个人的体验更加吸引人和沉浸式。
在我为他的网站设计的这个删除场景中,可以看到我为Mike Worth创建的猩猩冒险吉祥物驾车穿越景观。为了帮助讲述他被他的死对头从远处监视的故事,我想添加一个双筒望远镜形状的遮罩。
我首先创建了双筒望远镜形状,包括一些取景器标记。
然后,我将该图像应用为遮罩,设置其位置、重复和大小值,将其放置在figure元素的中心:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的旅程动画与双筒望远镜形状遮罩[forked] by Andy Clarke。
然而,尽管有无限滚动的背景和英雄颠簸行驶的运动,动画仍然感觉静态。因此我添加了一个微妙的动画,移动mask-position,首先创建关键帧:
|
|
然后,我将其与滚动背景动画一起应用到figure元素:
|
|
看到这些结果后,我想知道我是否可以通过将mask-position连接到某人光标的移动来将他们与故事联系起来。我添加了一个脚本,选择figure元素,获取光标相对于视口的位置,并动态改变mask-position:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的旅程动画与双筒望远镜跟随光标[forked] by Andy Clarke。
这样,只剩下一个挑战来完成效果。用双筒望远镜聚焦远处的目标很少容易,当英雄的死对头的手有银背大猩猩那么大时,任务更加困难。我扩展了我的脚本,模糊通过双筒望远镜形状遮罩看到的可见内容,然后在某人按下键盘的空格键或按下鼠标按钮时移除滤镜:
|
|
自己尝试一下: 参见CodePen上的Mike Worth的旅程动画与聚焦模糊[forked] by Andy Clarke。
更多遮罩动画
当使用Mike Worth网站的人跟随错误的路径或走错方向时,他最终会沉入热熔岩中。
为了让某人知道他们可能已经到达冒险的终点,我想模仿本文开头的缩放效果:
|
|
我创建了一个圆形clip-path,并将其默认大小设置为75%。然后,我定义了动画关键帧,将圆从75%调整到15%,然后将其附加到我的figure,持续一秒,延迟三秒:
|
|