复杂的形状

Web 功能: 遮罩 SVG

概览

如需将元素剪裁为复杂的自由形式形状(例如笔触或有机纹理),请使用 CSS 遮罩 (mask-image)。虽然 clip-path 非常适合几何形状或矢量路径,但 mask-image 允许您使用图片(例如具有透明度的 PNG)或 SVG 来定义元素的可见区域。这种方法更具表现力,因为它支持半透明,可实现柔和的边缘和复杂的纹理,而这些效果使用 clip-path 很难或无法实现。

实现

如需使用 CSS 遮罩实现复杂形状,请执行以下操作:

使用图片中的透明度

您可以将图片的透明度用作遮罩,其中不透明部分可见,透明部分隐藏。这可以是 PNG、SVG 或其他具有透明度的图片,也可以是生成的图片,例如 CSS 渐变。

.shaped-element {
  /* MANDATORY: Use vendor prefix for wider support in older browsers */
  -webkit-mask-image: url('mask.svg');
  -webkit-mask-size: cover; /* Scale mask to cover element */
  -webkit-mask-repeat: no-repeat; /* Do not tile the mask */

  /* Standard property for modern browsers */
  mask-image: url('mask.svg');
  mask-size: cover;
  mask-repeat: no-repeat;
}

在 HTML 中使用 SVG 元素

您还可以引用网页 HTML 中内嵌 SVG 内定义的 <mask> 元素。使用 maskContentUnits="objectBoundingBox" 可使遮罩随元素的大小自动缩放。这会告知浏览器将遮罩内的所有坐标解读为 0 到 1 之间的分数(例如 0.5 表示 50%),而不是绝对像素。

亮度遮罩与 Alpha 遮罩:默认情况下,SVG 遮罩使用亮度(明暗度)来确定不透明度,其中白色表示显示,黑色表示隐藏,灰色表示半透明。如果您希望遮罩改用 SVG 形状的 Alpha 通道(透明度),可以在 CSS 中指定 mask-type: alpha;,或直接在 SVG <mask> 元素上指定 mask-type="alpha"。

<!-- White areas reveal content, gray creates semi-transparency, black or transparent hides it -->
<svg width="0" height="0">
  <defs>
    <!-- objectBoundingBox scales mask coordinates (0 to 1) with the element's size -->
    <mask id="custom-shape" maskContentUnits="objectBoundingBox">
      <!-- Use white shapes to define fully opaque areas -->
      <circle cx="0.5" cy="0.5" r="0.5" fill="white" />
      <!-- Use gray shapes to define semi-transparent/faded areas -->
      <circle cx="0.5" cy="0.5" r="0.25" fill="gray" />
    </mask>
  </defs>
</svg>

<div class="masked-content">
  <!-- Content to be masked -->
</div>

<style>
.masked-content {
  /* Reference the SVG mask ID */
  -webkit-mask-image: url(#custom-shape);
  mask-image: url(#custom-shape);
}
</style>

后备策略

如果浏览器不支持 mask-image 或带前缀的版本:

  • 该元素不会被剪裁,而是显示为普通矩形。
  • 确保在没有遮罩的情况下,内容仍然可读,且布局不会损坏(渐进增强)。
  • (可选)使用特征检测功能,通过 clip-path 提供更简单的后备形状。
/* Fallback for browsers that do not support masking */
@supports (not (mask-image: url(x))) and (not (-webkit-mask-image: url(x))) {
  .shaped-element {
    /* Use a simple rounded rectangle as fallback */
    clip-path: inset(5% round 15px);
  }
}