使用 shape() 进行自适应剪裁

发布时间:2025 年 4 月 8 日

借助 clip-path 属性,您可以通过剪裁成圆形、多边形甚至 SVG 路径来更改元素的形状。不过,在 Chrome 135 和 Safari 18.4 之前,您必须在自适应多边形和使用 SVG 路径的非自适应复杂形状之间做出选择。借助新的 shape() 函数,clip-path 可以将元素剪裁为非多边形形状,并且该形状也具有自适应性。

Browser Support

  • Chrome: 135.
  • Edge: 135.
  • Firefox: 148.
  • Safari: 18.4.

Source

创建旗帜形状

例如,比较使用 clip-path: path()clip-path: shape() 创建旗帜形状。

一个绿色旗帜形状,顶部和底部有曲线。

旗帜形状并非完全是多边形,因为其顶部和底部边框是三次贝塞尔曲线,而不是直线或圆角。

使用 clip-path: path() 创建标志

可以使用 SVG 路径表示如下所示的旗帜形状:

.flag {
  clip-path: path(
    "M 0 20 \
     C 25 0 75 40 100 20 \
     V 80 \
     C 75 100 25 60 0 80 \
     z");
}

具体来说,SVG 路径是一系列路径命令:

  1. 移至 0、20。
  2. 曲线到 100、20,使用控制点 (25,0 和 75, 40)。
  3. 竖线到 80。
  4. 曲线到 0、80,使用控制点 (75,100 和 25,50)。
  5. 关闭路径(将线条连接到 0,20)。

这会绘制一个旗帜形状,但所有单位均为像素。 SVG 可以将这些像素缩放到视口,但始终看起来像是整个形状的几何缩放。

例如,如果您希望整个矩形进行缩放,但保持曲线的高度和宽度为 20 像素,则 SVG 无法完成此任务。

使用 shape() 创建标志

使用 shape() 比较相同的结果。形状函数接受一系列命令,类似于 SVG 路径命令。不过,这些命令接受 CSS 长度和百分比,以任何 CSS 单位表示。

以下 CSS 会将标志 shape() 转换为百分比单位:

.flag {
  clip-path: shape(from 0% 20%,
     curve to 100% 20% with 25% 0% / 75% 40%,
     vline to 80%,
     curve to 0% 80% with 75% 100% / 25% 60%,
     close
  );
}

使其具有自适应性

您可以从各种 CSS 长度中选择要用于每个坐标的长度。

例如,如需使标志的整体大小随元素的大小而缩放,但保持曲线的高度不变,您可以执行以下操作:

.flag {
  clip-path: shape(from 0% 20px,
     curve to 100% 20px with 25% 0% / 75% 40px,
     vline to calc(100% - 20px),
     curve to 0% calc(100% - 20px) 
           with 75% 100% / 25% calc(100% - 40px),
     close
  );
}

添加自定义属性和动画

现在,形状已在 CSS 中定义,您还可以使用自定义属性轻松操控高度:

.flag {
  --wave-height: 40px;
  clip-path: shape(
    from 0px var(--wave-height),
    curve to 100% var(--wave-height) 
          with 25% 0px / 75% calc(var(--wave-height) * 2),
    vline to calc(100% - var(--wave-height)),
    curve to 0 calc(100% - var(--wave-height))
          with 75% 100% / 25% calc(100% - var(--wave-height) * 2),
    close
  )
}

您甚至可以使用 @property 描述符为 CSS 属性设置动画效果,并对其进行限制,使其不会超出范围:

@property --animated-wave-height {
  syntax: "<length>";
  inherits: false;
  initial-value: 40px;
}

@keyframes curve {
  from { --animated-wave-height: 0px; }
  to { --animated-wave-height: 180px; }
}

.flag {
  width: 600px;
  height: 400px;
  background: green;
  animation: curve 1s infinite alternate;
  --wave-height: calc(min(var(--animated-wave-height, 40px), 40%));
  clip-path: shape(
    from 0px var(--wave-height),
    curve to 100% var(--wave-height)
          with 25% 0px / 75% calc(var(--wave-height) * 2),
    vline to calc(100% - var(--wave-height)),
    curve to 0 calc(100% - var(--wave-height)) 
          with 75% 100% / 25% calc(100% - var(--wave-height) * 2),
    close
  )
}

试用演示

在 Chrome 135 或 Safari 18.4 中,您可以在此 CodePen 演示中看到使用 clip-path: shape() 创建的动画旗帜形状。

摘要

clip-path: shape() 可让您使用任意响应式形状剪裁元素,而以前只能使用圆锥渐变或 JavaScript 构建的 SVG 等技术来实现。

如需查看完整语法,请参阅规范

目前,它仅适用于 clip-path。未来,我们计划使用这种形状来设置元素边框的形状,从而实现更多非矩形表达方式。