使用 CSS 蒙版创建锯齿状边缘

Avatar of Stuart Langridge
Stuart Langridge

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

我正在做一个项目,该项目在横幅图像底部有一个整洁的锯齿状边缘。

看起来很锐利……不止一种方式。

这让我思考了一下,在这个过程中我学到了一些东西! 我想我会写下我如何处理它,以便您可以在自己的项目中使用它。

我从一个包装元素中的老式 HTML 图像开始

<div class="jagged-wrapper">
  <img src="path-to-image.jpg" />
</div>

然后我使用它的::after伪元素在其上放置一个重复的背景图像

.jagged-wrapper::after {
  content: "";
  background-image: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="none"><polygon style="fill:white;" points="1,0 1,1 0,1 "/></svg>');
  background-size: 30px 30px;
  width: 100%;
  height: 30px;
  position: absolute;
  bottom: 0px;
  right: 0;
  z-index: 2;
}

那个背景图像?它是转换为数据 URI 的 SVG 代码。这是 原始 SVG 代码。Chris 制作了一个不错的视频,其中他介绍了转换过程

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1" preserveAspectRatio="none">
  <polygon style="fill: white;" points="1,0 1,1 0,1 "/>
</svg>

“搞定了!”我想。

虽然这确实有效,但天哪,这太麻烦了。很难像那样在 CSS 中读取 SVG 标记。此外,必须记住引用它们(例如url('data:image/svg+xml'...))也很烦人。当然,我们可以对 SVG 进行 Base64 编码以避免这种情况,但这更烦人。此外,SVG 需要填充与图像(或使用它的任何位置)相同的背景颜色,否则将无法正常工作。

等等,这不是蒙版的作用吗?是的!是的,这正是蒙版的作用。

这让我采用了新的方法:使用类似于上图的图像作为 CSS 蒙版,以便横幅图像的“缺失”部分实际上确实缺失。与其在横幅顶部绘制背景色的三角形,不如将这些三角形完全从横幅中遮蔽掉,并让真实的背景透出来。这样,它适用于任何背景!

蒙版在几乎所有地方都得到了很好的支持——至少在我这里讨论的简单方法中是这样。我们也在讨论可以通过渐进增强实现的东西;如果在给定的浏览器中不支持蒙版,那么您就不会获得锯齿效果。绝对不是世界末日。

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

桌面

ChromeFirefoxIEEdgeSafari
1205312015.4

移动/平板电脑

Android ChromeAndroid FirefoxAndroidiOS Safari
12712712715.4

CSS 蒙版的工作原理之一是提供具有 alpha 通道的图像作为mask-image。被遮蔽的基础元素——即被遮蔽的元素——会根据mask-image的 alpha 通道变得(半)透明。因此,如果您的蒙版图像是在透明背景上的白色茶壶,则被遮蔽的元素将被裁剪成茶壶的形状,并且外部的所有内容都将被隐藏。

蒙版可能是一个难以理解的概念。Sarah Drasner 有一篇文章深入探讨了蒙版,包括它与裁剪的不同之处。蒙版可以做的事情远不止我们在这里介绍的内容。查看规范caniuseMDN以获取更多信息。

我们需要一个类似于上面 SVG 的单个“锯齿状”图像,其中左上半部分填充白色,左下半部分保持半透明。并且,理想情况下,该图像不是实际的 SVG,因为这会让我们回到之前遇到的丑陋的数据 URI 混乱中。

此时您可能正在想:“嘿,只需将 SVG 直接嵌入到 CSS 中,在其中定义一个蒙版,然后将 CSS 指向 SVG 中的蒙版 ID!”

好主意!如果您可以编辑 HTML,这当然是可以做到的。但是,对于我的特定项目,我是在 WordPress 中工作的,我真的很想将我的更改限制在纯 CSS 中,而不是将额外部分注入 HTML 中。那将需要更多工作。我认为这并不罕见;对于像这样的表现性更改,无需编辑 HTML 非常有用。我们大多赞同避免语义上毫无价值的包装元素以提供样式挂钩的想法,但我认为这也适用于向文档添加整个 SVG 标记……甚至 WordPress 模板。

我们可以使用 CSS 线性渐变 来创建三角形形状

.el {
  linear-gradient(
    to bottom right,
    white,
    white 50%,
    transparent 50%,
    transparent
  );
}

它在径向背景上,因此您可以看到它是真正透明的

太棒了!我们可以将其用作横幅的mask-image,对吧?我们需要设置mask-size(类似于background-size)和mask-repeat(类似于background-repeat),然后我们就完成了?

不幸的是,不。情况并非如此。

第一个原因是,除非您使用 Firefox,否则您可能会在上面的示例中根本看不到任何蒙版。这是因为在撰写本文时,Blink 和 WebKit 仍然只支持带供应商前缀的蒙版。这意味着我们需要-webkit-版本的前缀。

除了供应商前缀之外,我们所做的事情在概念上也是错误的。如果我们将蒙版限制在图像的底部条带上使用mask-size,那么图像的其余部分将根本没有mask-image,这会将其完全遮蔽掉。因此,我们不能单独使用锯齿作为蒙版。我们需要一个mask-image,它是一个与图像大小相同的矩形,底部只有一个锯齿。

类似于此

我们使用两个渐变图像来实现这一点。第一个图像是与上面相同的锯齿三角形,设置为repeat-x并位于bottom位置,以便它仅沿图像的底部边缘重复。第二个图像是另一个渐变,对于底部 30px 透明(以免干扰锯齿),在其上方不透明(在演示中显示为从黑色到白色),并占据元素的整个大小。

因此,我们现在有了这个楔形块,底部有一个三角形锯齿,它由两个单独的部分占据横幅图像的整个高度。最后,我们可以通过水平重复这些部分来使用mask-image,它应该具有我们想要的效果

就是这样!