CSS 中的裁剪和蒙版

Avatar of Chris Coyier
Chris Coyier 发布

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

这两种方法都用于隐藏元素的某些部分并显示其他部分。但是,它们之间当然存在差异。它们在功能、语法、所涉及的技术、新旧版本以及浏览器支持方面的差异。

不幸的是,市面上有很多过时的信息。让我们看看是否可以将其整理出来。

裁剪和蒙版的区别

蒙版是图像;裁剪是路径。

想象一个方形图像,它是一个从左到右的黑色到白色的渐变。这可以是一个蒙版。应用到它的元素将在渐变蒙版图像为黑色的地方是透明的(可见),而在白色的地方是不透明的(正常的)。因此,最终结果将是一个从左到右逐渐淡入的元素。

裁剪始终是矢量路径。路径外部是透明的,路径内部是不透明的。

我个人觉得这很混乱,因为你经常会看到关于蒙版的教程,它们使用一个白色矢量形状在黑色背景上的蒙版图像,所以它基本上是在做与裁剪相同的事情。这没问题,只是有点混乱。

旧的/已弃用的 clip

CSS 中裁剪的首次出现(除了 overflow: hidden; 技巧)是 clip 属性。(MDN)。

它就像这样

.element {
  clip: rect(10px, 20px, 30px, 40px);
}

这四个值与 margin/padding 的顺序相同

  • 元素顶部 10px
  • 元素右侧 20px
  • 元素底部 30px
  • 元素左侧 40px

clip 属性在 CSS 中已弃用,这意味着不建议使用它,因为有一个更新的、标准化的版本,浏览器将专注于这个版本。

clip 有一些优点:由于 clip 已在浏览器中发布,因此它可能永远有效。它对浏览器的支持也非常强大:几乎所有浏览器都支持它。另外,我听说它的动画性能超过了更新的方法。

但是,clip 有两个相当重要的缺点,这使得不使用它更容易接受

  • clip 仅在元素绝对定位时才有效
  • clip 只能做矩形。

非常有限。所以让我们继续前进。

新的 clip-path

在 CSS 中应用裁剪到元素的新推荐版本是 clip-path。你可能会认为它很简单,就像

.element {
  /* NOPE */
  clip-path: rect(10px, 20px, 30px, 40px);
}

但这行不通(即使带前缀,在任何地方)。最终,我们将得到 rectangle(),只是 还没有

将 rectangle() 推迟到第 2 级

新的方法是使用 inset()

.element {
  clip-path: inset(10px 20px 30px 40px);
  /* Also can take single values to make all sides the same, or 2 values (vert/horz), or 3 values (top/horz/bottom). */
}

注意,没有逗号,并且 语法不同,但最终执行的是相同类型的操作。

clip-path 中同样有效的(在一些浏览器中)是圆形、椭圆形和多边形。这里有一些示例

.clip-circle {
  clip-path: circle(60px at center);
  /* OLD VALUE example: circle(245px, 140px, 50px); */
  /* Yep, even the new clip-path has deprecated stuff. */
}
.clip-ellipse {
  clip-path: ellipse(60px 40px at 75px 30px);
  /* OLD VALUE example: ellipse(245px, 80px, 75px, 30px); */
}
.clip-polygon {
  clip-path: polygon(5% 5%, 100% 0%, 100% 75%, 75% 75%, 75% 100%, 50% 75%, 0% 75%);
  /* Note that percentages work as well as px */
}

查看 CodePen 上 Chris Coyier 的 clip-path 示例。(@chriscoyier

多边形非常强大。Ryan Scherf 在这里发布了一个教程,介绍如何在 CSS-Tricks 上使用它以编程方式创建草图效果。

我强烈建议使用 Bennet Feely 的 Clippy 来试用它。

理论上,这就是 clip-path 将支持的内容(被称为“基本形状”)

.clip-examples {

  clip-path: rectangle(x, y, width, height, rounded-x, rounded-y)
          
  clip-path: inset-rectangle(from top, from right, from bottom, from left, rounded-x, rounded-y)
  /* Looks like this is what rect() used to be like with clip */
  /* Will replace inset(), I suppose */

  clip-path: polygon(a, bunch, of, points)
  clip-path: circle(radius at x, y)
  clip-path: ellipse(radius-x, radius-y at x, y)

}

我似乎找不到关于 path() 是否会成为有效值的信息。

使用带 SVG 定义的 的 clip-path

您不必在 CSS 中直接定义 clip-path 值,它可以引用在 SVG 中定义的 <clipPath> 元素。以下是它的外观

<img class="clip-svg" src="harry.jpg" alt="Harry Potter">

<svg width="0" height="0">
  <defs>
    <clipPath id="myClip">
      <circle cx="100" cy="100" r="40" />
      <circle cx="60" cy="60" r="40" />
    </clipPath>
  </defs>
</svg>
.clip-svg {
  clip-path: url(#myClip);
}

演示

查看 CodePen 上 Chris Coyier 的 clip-path 示例。(@chriscoyier

Sara Soueidan 有一个演示展示了它的实际操作方式。

但是,使用 SVG 定义的裁剪路径有一个相当重要的问题:一些浏览器会将它们固定到文档的左上角。这里有一个演示展示了这个问题

左侧:裁剪路径在 Google Chrome 54 中与图像一起移动(正常)。右侧:裁剪路径固定在左上角,不会与图像一起移动(错误)。

动画/过渡 clip-path

当您将基本形状声明为裁剪路径时,可以对其进行动画处理!Dirk Schulze 有一篇很棒的文章介绍了这种相同的东西,它包含这个演示

查看 CodePen 上 Chris Coyier 的 很棒的 clip-path 动画。(@chriscoyier

这是一个简单的代码示例

div {
  transition: 0.4s cubic-bezier(1, -1, 0, 2);
  clip-path: polygon(50% 5%, 0% 100%, 100% 100%);
}
div:hover {
  clip-path: polygon(50% 19%, 0 76%, 100% 76%);
}

试一试

查看 CodePen 上 Chris Coyier 的 过渡 clip-path。(@chriscoyier

蒙版

曾经有一个 WebKit 专属的蒙版版本,您可以在其中链接一个光栅图像或定义一个渐变作为蒙版。它看起来像这样

img {
  width: 150px;
  -webkit-mask-image: -webkit-gradient(
    linear, left top, right bottom, 
    color-stop(0.00,  rgba(0,0,0,1)),
    color-stop(0.35,  rgba(0,0,0,1)),
    color-stop(0.50,  rgba(0,0,0,0)),
    color-stop(0.65,  rgba(0,0,0,0)),
    color-stop(1.00,  rgba(0,0,0,0)));
}

据我所知,这已经弃用。这是肯定已弃用的渐变语法,当我将其更改为新语法时,它不起作用。所以是的,可能已弃用。但它仍然有效

查看 CodePen 上 Chris Coyier 的 旧的 WebKit 蒙版。(@chriscoyier

它催生了像这个旧教程 WebKit 图像擦除 之类的东西,它仍然有效(您知道,在 Blink/WebKit 环境中)。

我发现的更现代的参考资料只提到了蒙版是在 SVG 中定义的,并在 CSS 中通过 ID 或 URL 引用。以下是一个通过两种方式实现的示例。蒙版在 SVG 中定义,左侧的图像通过一个 标签位于 SVG 中。右侧的蒙版应用到 HTML 中的 (目前似乎只在 Firefox 中有效)。

查看 CodePen 上 Chris Coyier 的 41d6e36ac584ee0401064d1cdb88fc67。(@chriscoyier

在 Firefox 中查看此演示(示例代码摘自 Dirk Shulze 的文章)。这种方法目前有点危险,因为它在 WebKit/Blink 中不仅不起作用,还会完全擦除应用到它的元素。

您还可以将整个 SVG 文件链接为蒙版,例如

.mask {
  mask: url(mask.svg);
}

蒙版类型

.mask {
  mask-type: luminance; /* white = transparent, grays = semi-transparent, black = opaque */
  mask-type: alpha; /* transparent areas of the image let image through, otherwise not */
}

边框蒙版

这与 CSS 中的 边框图像工作原理 非常相似。您定义一个 SVG 图像,并应用九宫格缩放(就像在图像上覆盖了一个井字格)。角部用于角部,边缘(可以)沿着边缘重复,中间(可以)在中间拉伸。这就是基本原理

.border-mask {
  /* Note that the properties aren't quite the same */
  -webkit-mask-box-image: url(stampTiles.svg) 30 repeat;
  mask-border: url(stampTiles.svg) 30 repeat;
  /* Image, again, from http://www.html5rocks.com/en/tutorials/masking/adobe/ */
}

以下是对普通蒙版与边框蒙版的演示

查看 CodePen 上 Chris Coyier 的 使用 SVG 图像的 CSS 蒙版。(@chriscoyier

浏览器支持

很难简洁地概括,因为不同的属性,甚至 *值* 在不同的浏览器中都有不同的支持程度。更不用说如何使用它们以及在什么地方使用它们了。这是一个荒野,所以我建议在目前尽量使用渐进增强。这可能有点困难,因为目前还没有 Modernizr 对这些内容进行测试。

关于前缀:在几乎所有内容上都使用无前缀和 -webkit- 前缀。

Yoksel 制作了一张很棒的浏览器支持图表,与所有这些内容相关。

查看 CodePen 上 yoksel 的笔:CSS 和 SVG 蒙版 (@yoksel)。

更多