这两种方法都用于隐藏元素的某些部分并显示其他部分。但是,它们之间当然存在差异。它们在功能、语法、所涉及的技术、新旧版本以及浏览器支持方面的差异。
不幸的是,市面上有很多过时的信息。让我们看看是否可以将其整理出来。
裁剪和蒙版的区别
蒙版是图像;裁剪是路径。
想象一个方形图像,它是一个从左到右的黑色到白色的渐变。这可以是一个蒙版。应用到它的元素将在渐变蒙版图像为黑色的地方是透明的(可见),而在白色的地方是不透明的(正常的)。因此,最终结果将是一个从左到右逐渐淡入的元素。
裁剪始终是矢量路径。路径外部是透明的,路径内部是不透明的。
我个人觉得这很混乱,因为你经常会看到关于蒙版的教程,它们使用一个白色矢量形状在黑色背景上的蒙版图像,所以它基本上是在做与裁剪相同的事情。这没问题,只是有点混乱。
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()
是否会成为有效值的信息。
的 clip-path
使用带 SVG 定义的 您不必在 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 定义的裁剪路径有一个相当重要的问题:一些浏览器会将它们固定到文档的左上角。这里有一个演示展示了这个问题
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)。
更多
- clip-path 在 CSS-Tricks 年鉴上。
- CSS 中的裁剪和蒙版
- WPD 上的 clip-path
- MDN 上的 clip-path
- MDN 上的裁剪和蒙版
- (已弃用)CSS 剪切属性(Impressive Webs)
- CSS 蒙版规范
- CSS 蒙版 由 Dirk Schulze 撰写。
- CSS 和 SVG 中的裁剪 - clip-path 属性和
<clipPath>
元素 由 Sara Soueidan 撰写。 - CodePen 上带有 clip-path 标签的笔
- 演示和浏览器支持演示笔 由 Yoksel 撰写。
- SVG 蒙版 由 Jakob Jenkov 撰写。
- Alan Greenblatt 的 裁剪和蒙版功能的浏览器支持级别研究
- 演讲视频:Razvan Caliman - 图形的前沿 CSS 功能:CSS 蒙版、混合和形状
我相信
clip-path: inset()
的工作方式与clip: rect()
相同。clip-path: inset()
在当前支持 clip-path 的浏览器中有效。我还没有听说过rect()
、rectangle
、inset-rectangle
或其他任何东西的新消息。是的,谢谢!Ana Tudor 在我发布之后也向我指出了这一点。这就是为什么我很幸运能写这样的文章,因为我从反馈中学到的东西和从研究中学到的东西一样多。
请参阅我下面的原始评论 - 我可能应该一开始就在这里回复。
旧的
clip: rect()
和新的clip-path: inset()
在解释 4 个参数方面有很大不同:rect()
对所有参数从顶部/左侧进行解释,inset()
从 4 个边中的每一个进行解释。“我可能只是漏掉了什么,但我没有找到让路径随着它应用到的元素一起移动的明显方法。”
它在 Firefox(这里为 34)中有效。所以,要么 Firefox 使它在不应该的情况下有效,要么 WebKit/Blink 实现在这方面存在错误。
Firefox 还将 SVG 蒙版的两个圆圈放在更右边和更左边,这看起来像是您从 SVG 代码中期望的结果(我可能错了)。
对我也有效,FF 34.0.5 beta。
那里肯定有些奇怪的东西。即使我做错了什么(很可能),跨浏览器的行为应该是一样的。所以有人有错误,只是不清楚是谁。
很棒的文章... 文章没有明确地说,但你也可以使用 PNG 图像作为蒙版...
裁剪和蒙版就像 flexbox 那样,我想在今天的想法中使用它们,但不能完全确定它是否会在跨浏览器上运行。好的一点是,主要的浏览器在实现像这样的新事物方面越来越快,所以我对寻找更多新进展非常乐观。
很高兴看到你很了解 Chris,并把这些技巧传播给其他人。谢谢!
这是 SVG 剪切路径的默认行为:包含的图形在用户坐标系中定义。但是,您可以通过设置
<clipPath>
元素上的clipPathUnits
属性来控制它。默认值为userSpaceOnUse
,另一个选项是objectBoundingBox
。请注意,如果您使用objectBoundingBox
,不仅原点会改变,而且单位的定义也会改变 - 长度为 1 被视为长度为 100%。那么,这如何应用于非 SVG 内容?用户坐标系和对象边界框是如何定义的?不幸的是,规范有点混乱(这可能解释了跨浏览器问题)。
裁剪和蒙版规范链接到 CSS 变换规范中用户坐标的以下定义
由于
transform-box
的默认值为border-box
,看起来 Firefox 是正确的,并且被裁剪元素的用户坐标系应该随着元素本身一起移动。同时,您可以使用
objectBoundingBox
单位获得跨浏览器结果http://codepen.io/AmeliaBR/pen/RNWyYJ?editors=110
但是,有一个复杂之处。CSS 蒙版规范使用以下定义
最后一句话与 objectBoundingBox 在 SVG 中的工作方式以及浏览器当前实现它的方式(测试了 FF 和 Chrome)不一致。我将在 W3C 邮件列表中跟进 - 这可能是一个错误,或者可能存在我遗漏的某个非标准的“用户坐标”定义(在 SVG 中,“用户坐标”意味着“没有单位指定的坐标”,当处理边界框坐标系时,这些坐标会变成宽度/高度)。
同时,如果您想更加确定,可以在 objectBoundingBox 剪切路径中使用百分比而不是小数。
关于蒙版与裁剪要提到的另一件事是,蒙版更占内存和计算量,因为它是一个完整的图像,并且必须逐像素地处理所有内容。因此,只有在您确实想要获得部分透明度效果时才使用蒙版;对于清晰的边缘,请使用剪切路径。
当然,鉴于兼容性讨论令人失望的结果,看起来蒙版在一段时间内对非 SVG 内容来说不会很实用,所以这是使用剪切路径的另一个原因!
这是一个雷区,没有办法绕过。看起来它可能很棒,并打开一个全新的技巧世界,如果它最终得到正确地最终确定的话。在 10 年内了解网络将非常有用;)
你可以用变换来移动它。(在 chrome 中测试过)例如
很棒的文章!我很高兴 css3 走到了这一步,我也喜欢最近发生的这种 svg-css 的爱情故事。关于 clip-path 被修复的错误,你尝试过将动画放在图像的父元素上吗?
这些路径动画太棒了。感谢分享。
非常酷而且有用!
感谢发布。
它有效,谢谢,真的很酷
我认为这在以上技术中没有提到,但我通过将遮罩和图像都保留在 SVG 中来实现了类似的效果。 显然,这不会给你提供 CSS 的灵活度,但如果你有一种从例如 CMS 生成此 SVG 代码的方法,它还是很容易管理的。
查看 Pen SVG 图像作为遮罩 by tobystokes (@tobystokes) on CodePen.
“看起来这就是 rect() 以前用作裁剪的方式”
除了这对于我目前正在做的一个项目非常有用之外,我还很喜欢这篇文章中对哈利波特的自由使用 :D
太棒了!几周前我刚想知道这个问题,因为我想在没有 After Effects 的情况下动画化一个未来派的滑动 UI。
嘿,Chris,很棒的文章!
我认为文章中对旧的
clip: rect()
的定义有点偏差,以及与较新的clip-path: inset()
的比较。clip: rect()
东西采用 4 个参数来裁剪边,但它们标记的是距顶部/左侧边缘的距离,而不是距所有 4 个边缘的距离。第一个参数是从顶边边缘裁剪的顶部距离,第二个参数是从左侧边缘裁剪的右侧距离,第三个参数是从顶部边缘裁剪的底部距离,第四个参数是从左侧边缘裁剪的左侧距离。
(旁注:这就是旧的
clip: rect(0 0 0 0)
技术用于可访问的隐藏技术(如 Snook 的示例 中的技术)的原因——它可以轻松地裁剪掉整个元素,而无需了解尺寸。)然而,
clip-path
的inset()
符号确实是从 4 个边框边缘开始工作的,因此它会产生完全不同的(并且可以说更灵活的)结果。我创建了一个简单的 JSBin 示例来说明差异。
嘿,Chris(和朋友们),
首先——非常感谢你很棒的网站。它对我们所有人来说都是一个很棒的资源,所以感谢你不断地用新鲜且相关的文章来更新它。 基本上,你很棒。
我想知道关于遮罩(或裁剪)div(或任何其他元素)的最佳方法是什么。 你上面建议的示例似乎主要与图像相关,这很棒且非常有用,但我想知道,例如,如果我有一个 html5 视频甚至 youtube 嵌入,我想对其应用裁剪路径或遮罩,最好的方法是什么? 我以前听说过 canvas,但有没有办法通过 css 来实现呢?
敬上。