几周前,我偶然发现了 这个很酷的弹出效果,由 Mikael Ainalem 创建。它展示了 CSS 中的 clip-path: path()
,该属性在大多数现代浏览器中获得了 良好的支持。我想自己深入研究一下,以便更好地了解其工作原理。但在过程中,我发现 clip-path: path();
存在一些问题,并最终找到了一种替代方法,我想在本文中与大家一起探讨。
如果您从未使用过 clip-path
或不熟悉它,它基本上允许我们根据剪辑路径 指定元素的显示区域,并隐藏落在剪辑路径之外的元素部分。

clip-path
的可能值包括 circle
、ellipse
和 polygon
,这些值将用例限制在这些特定形状。这就是新的 path
值的用武之地——它允许我们使用更灵活的 SVG 路径来创建各种超出基本形状的剪辑路径。
让我们利用我们对 clip-path
的了解,开始着手处理悬停效果。其基本思想是使人物的前景图像从彩色背景中弹出,并在元素悬停时放大。一个重要的细节是如何使前景图像动画(放大和向上移动)看起来与背景图像动画(仅放大)独立。
这种效果看起来很酷,但 path
值存在一些问题。首先,虽然我们提到支持总体上不错,但并不完美,并且在撰写本文时,其覆盖率 约为 82%。因此,请记住,移动设备支持目前仅限于 Chrome 和 Safari。
除了支持之外,path
的另一个更大、更奇怪的问题是,**它目前仅适用于像素值**,这意味着 它没有响应性。例如,假设我们放大页面。一开始,路径形状就开始裁剪内容。


这严重限制了 clip-path: path()
的用例数量,因为它只能用于固定大小的元素。响应式网页设计多年来一直是广泛接受的标准,因此看到一个不遵循该原则并专门使用像素单位的新 CSS 属性,这很奇怪。
我们将要做的就是使用标准的、广泛支持的 CSS 技术重新创建此效果,以便它不仅可以正常工作,而且真正具有响应性。
棘手的部分
我们希望任何超出 clip-path
的内容仅在图像的顶部可见。我们不能使用标准的 CSS overflow
属性,因为它会影响顶部和底部。

overflow-y: hidden
,底部看起来不错,但图像在顶部被裁剪掉了,而那里应该可见溢出内容。那么,除了 overflow
和 clip-path
之外,我们还有哪些选择?好吧,让我们在 SVG 本身中使用 <clipPath>
。<clipPath>
是一个 SVG 属性,它与新发布且无响应的 clip-path: path
不同。
<clipPath>
元素
SVG SVG <clipPath>
和 <path>
元素适应 SVG 元素的坐标系,因此它们天生就具有响应性。随着 SVG 元素的缩放,其坐标系也会缩放,并且根据 各种属性 保持其比例,这些属性涵盖了各种可能的用例。作为额外的好处,在 SVG 上使用 CSS 中的 clip-path
具有 95% 的浏览器支持,与 clip-path: path
相比增加了 13%。
让我们从设置 SVG 元素开始。我使用了 Inkscape 来创建基本的 SVG 标记和剪辑路径,以便于操作。完成此操作后,我通过添加自己的类属性更新了标记。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -10 100 120" class="image">
<defs>
<clipPath id="maskImage" clipPathUnits="userSpaceOnUse">
<path d="..." />
</clipPath>
<clipPath id="maskBackground" clipPathUnits="userSpaceOnUse">
<path d="..." />
</clipPath>
</defs>
<g clip-path="url(#maskImage)" transform="translate(0 -7)">
<!-- Background image -->
<image clip-path="url(#maskBackground)" width="120" height="120" x="70" y="38" href="..." transform="translate(-90 -31)" />
<!-- Foreground image -->
<image width="120" height="144" x="-15" y="0" fill="none" class="image__foreground" href="..." />
</g>
</svg>

<clipPath>
元素。绿色元素表示将应用于背景图像的剪辑路径。红色是将应用于背景和前景图像的剪辑路径。此标记可以轻松地重复用于其他背景和前景图像。我们只需要替换 image
元素内部 href
属性中的 URL。
现在我们可以处理 CSS 中的悬停动画。我们可以使用转换和过渡,确保前景居中,然后在悬停时缩放和移动内容。
.image {
transform: scale(0.9, 0.9);
transition: transform 0.2s ease-in;
}
.image__foreground {
transform-origin: 50% 50%;
transform: translateY(4px) scale(1, 1);
transition: transform 0.2s ease-in;
}
.image:hover {
transform: scale(1, 1);
}
.image:hover .image__foreground {
transform: translateY(-7px) scale(1.05, 1.05);
}
这是上述 HTML 和 CSS 代码的结果。尝试调整屏幕大小和更改 SVG 元素的尺寸,以查看效果如何随屏幕大小缩放。
看起来很棒!但是,我们还没有完成。我们仍然需要解决一些问题,这些问题是在我们将标记从 HTML 图像元素更改为 SVG 元素后出现的。
SEO 和可访问性
内联 SVG 元素 不会被搜索爬虫索引。如果 SVG 元素是内容的重要组成部分,则您的页面 SEO 可能会受到影响,因为这些图像可能不会被抓取。
我们需要使用常规 <img>
元素的其他标记,该元素使用 CSS 隐藏。以这种方式声明的图像会自动被爬虫抓取,并且我们可以在 图像站点地图 中提供这些图像的链接,以确保爬虫能够找到它们。我们使用 loading="lazy"
,它允许浏览器决定是否应延迟加载图像。
我们将两个元素都包装在 <figure>
元素中,以便 标记反映这两个图像之间的关系 并将其组合在一起。
<figure>
<!-- SVG element -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -10 100 120" class="image">
<!-- ... -->
</svg>
<!-- Fallback image -->
<img src="..." alt="..." loading="lazy" class="fallback-image" />
</figure>
我们还需要解决此效果的一些可访问性问题。更具体地说,我们需要为那些喜欢在没有动画的情况下浏览网页的用户以及使用屏幕阅读器浏览网页的用户进行改进。
使 SVG 元素可访问需要 大量额外的标记。此外,如果我们想删除过渡,则必须覆盖相当多的 CSS 属性,如果我们的选择器特异性不一致,这可能会导致问题。幸运的是,我们新添加的常规图像具有内置的出色可访问性功能,可以轻松地作为那些在没有动画的情况下浏览网页的用户替代方案。
<figure>
<!-- Animated SVG element -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -10 100 120" class="image" aria-hidden="true">
<!-- ... -->
</svg>
<!-- Fallback SEO & a11y image -->
<img src="..." alt="..." loading="lazy" class="fallback-image" />
</figure>
我们需要通过添加 aria-hidden="true"
来隐藏辅助设备中的 SVG 元素,并且我们需要更新 CSS 以包含 prefers-reduced-motion
媒体查询。我们 包含性地隐藏 了没有减少运动偏好的用户的回退图像,同时将其保留供屏幕阅读器等辅助设备使用。
@media (prefers-reduced-motion: no-preference) {
.fallback-image {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
}
@media (prefers-reduced-motion) {
.image {
display: none;
}
}
以下是改进后的结果。
请注意,这些改进不会改变没有设置 prefers-reduced-motion
偏好或未使用屏幕阅读器的用户的效果外观和行为。
总结
开发人员对 clip-path
CSS 属性的 path
选项以及新的样式可能性感到兴奋,但许多人发现这些值仅支持像素值后感到不快。这不仅意味着该功能没有响应性,而且严重限制了我们想要使用它的用例数量。
我们将一个有趣的图像弹出悬停效果(使用 clip-path: path
)转换为一个 SVG 元素,该元素利用 <clipPath>
SVG 元素的响应性来实现相同的效果。但在这样做的过程中,我们引入了一些 SEO 和可访问性问题,我们通过一些额外的标记和回退图像解决了这些问题。
感谢您抽出时间阅读本文!请告诉我这种方法是否让您想出了如何实现自己的效果,以及您是否有任何关于以不同方式处理此效果的建议。
我个人会将
overflow: hidden
与容器上的border-radius
结合使用。也许使用带有圆角的clip-path: inset()
。这里有一个 展示这两者的示例。前景图像元素上出现了一个非常奇怪的幽灵轮廓,在悬停时出现。看起来像是图像的边界框。
有什么想法导致了这种情况或如何解决它吗?
是的,我也注意到了。它似乎只在 Windows 上发生,并且可能发生在任何应用了
transform
的 SVG 上。我已经尝试了所有我能想到的方法来解决这个问题,但它可能与操作系统和浏览器而不是 SVG 和 CSS 相关。没错,macOS 上的 Google Chrome 也有同样的问题。
我曾经用纯 CSS 以响应式的方式做过类似的事情。这是一个 Stack Overflow 的问题,代码如下:https://codepen.io/t_afif/pen/poRPyPV.. 技巧是使用两个不同的图层创建人物图像,并且半径只会影响底层图层。然后您可以轻松调整尺寸、图像顶部和底部的偏移量。
一篇很棒的文章,展示了使用
clip-path: path
的能力。正如你总结的那样,这种技术有其自身的缺点,并且用例有点有限。在实现像这样的弹出效果方面,有一些更简单的方法,不需要同样的复杂性。这里有一个使用 border-radius 的示例:https://codepen.io/dannievinther/pen/yLgMdWO(快速示例)。
大家好,感谢分享你们自己的示例。很高兴学习新东西。
我还想指出,这种方法适用于任何背景形状(斑点、星星、椭圆等),因此此实现可以用于这些复杂形状。