CSS shape() 函数
形状是图形设计的重要方面。shape()
函数提供了一种新的方式来编写形状,这些形状可以根据元素的大小,以混合比例进行适应和缩放。
多年来,CSS 已经赋予 Web 开发者使用形状进行裁剪和动画的能力。形状最常见的用法是在clip-path
属性中。这会在元素布局完成后应用裁剪,允许你作为 Web 开发者进行一些操作,例如将边缘修剪成装饰性的波浪形状。这可以产生与遮罩相似的效果,但渲染效率比遮罩更高。形状的另一个用例是在offset-path
属性中,它允许你沿着路径对某个事物进行动画处理。最后,shape-outside
提供了一种使文本围绕非矩形形状环绕的方式(但目前仅支持部分形状类型)。
CSS 提供了一组形状,可以与这些属性配合使用。(在 Web 标准中,这些形状在基本形状中得到了完整定义。)有多种方式可以描述矩形,以及 circle()
和 ellipse()
、polygon()
(一组直线段)以及采用 SVG 样式路径的 path()
函数。
例如,考虑这个简单的箭头形状

生成此形状的 SVG 为
<svg viewBox="0 0 150 100" xmlns="http://www.w3.org/2000/svg">
<path fill="black" d="M0 0 L 100 0 L 150 50 L 100 100 L 0 100 Q 50 50 0 0 z " />
</svg>
我们稍后将分解此路径。现在,让我们将该路径应用于 clip-path
中的 HTML 元素
.clipped {
width: 150px;
height: 100px;
box-sizing: border-box;
background-color: blue;
border: 10px solid orange;
clip-path: path("M0 0 L 100 0 L 150 50 L 100 100 L 0 100 Q 50 50 0 0 z");
}
它产生如下效果

请注意我如何添加了边框,以便您可以看到 clip-path
是如何裁剪元素部分的。
但是,如果我们现在改变元素的尺寸会发生什么呢?例如,如果我们要一个更长的箭头呢?
.clipped {
width: 200px;
...
}
遗憾的是,我们得到了相同的形状,只是箭头的尖端不再显示边框。

这意味着在 clip-path
中使用 path()
无法实现响应式;你无法编写 CSS 规则,使路径适应元素的大小。这就是新的 shape()
函数发挥作用的地方。
shape()
新的 shape()
函数通过允许你使用已经熟悉的 CSS 关键字和单位来指定路径,包括 calc()
和 CSS 变量的全部功能,直接解决了这个响应性问题,而且它更具可读性。
让我们回到并分解那个看起来像一串难以理解的字母和数字的 SVG 路径:“M0 0 L 100 0 L 150 50 L 100 100 L 0 100 Q 50 50 0 0 z”。我们可以将其分解为一系列“命令”,这些命令描述了路径的每个部分
M 0 0 | 移动到 0, 0 |
---|---|
L 100 0 | 画线到 100, 0 |
L 150 50 | 画线到 150, 50 |
L 100 100 | 画线到 100, 100 |
L 0 100 | 画线到 0, 100 |
Q 50 50 0 0 | 二次贝塞尔曲线,控制点位于 50, 50,结束于 0, 0 |
z | 闭合路径 |
我们可以使用 CSS 规范中指定的名称将此路径转录成一个形状;请注意第一个“move”命令在 shape 中如何变为“from”
clip-path: shape(from top left,
line to 100px top,
line to 150px 50%,
line to 100px bottom,
line to bottom left,
curve to top left with 50px 50%,
close);
请注意,当点在绝对坐标中时,我们可以使用“top”和“bottom left”等关键字,并且我们可以使用百分比。
这给了我们与上面相同的结果,但我们还没有使其完全响应式。我们的下一步是使形状随元素的宽度水平拉伸,但将高度固定为 100px。让我们用一点数学来实现这一点。为了简化,我们将元素的期望高度放入一个变量中
.responsive-clip {
--height: 100px;
height: var(--height);
...
}
我们还将定义半高值,用于计算右侧的箭头形状,以及二次曲线的控制点。
--half-height: calc(var(--height) / 2);
形状的响应式部分可以用百分比来表示。x 坐标中使用的百分比是相对于元素宽度的,而 y 坐标中使用的百分比是相对于元素高度的
clip-path: shape(from top left,
line to calc(100% - var(--half-height)) 0%,
line to 100% var(--half-height),
line to calc(100% - var(--half-height)) 100%,
line to left bottom,
curve to left top with var(--half-height) var(--half-height),
close);
现在我们有了一个可以与元素一样长的剪辑!

使此形状适应元素的高度更为棘手,因为我们需要能够在水平轴上的值中引用高度。这是我们可以使用容器查询 (Container Queries) 实现的。首先,让我们在 HTML 标记中创建一个容器
<div class="responsive-clip-container">
<div class="responsive-clip"></div>
</div>
一旦我们定义了容器并将元素的尺寸移到那里,我们现在就可以将 var(--half-height)
替换为 50cqh
.responsive-clip-container {
width: 100%;
aspect-ratio: 5 / 1;
container-type: size;
}
.responsive-clip {
height: 100%;
background: blue;
border: 10px solid orange;
box-sizing: border-box;
clip-path: shape(from top left,
line to calc(100% - 50cqh) 0%,
line to 100% 50cqh,
line to calc(100% - 50cqh) 100%,
line to bottom left,
curve to top left with 50cqh 50cqh,
close);
}
让我们为容器添加一个调整器,以便您可以试用响应性!
.responsive-clip-container {
resize: both;
overflow: clip;
}
在 Safari 18.4 或其他支持的浏览器中尝试此演示。
CodePen 上创作的 Pen – 演示 3
在CodePen上。
调整箭头大小有助于真正展示 shape()
的功能。请注意曲线和 90 度角是如何保留的,这是拉伸 SVG 时无法实现的效果。
shape()
函数还有更多我们在此未提及的功能,例如相对而非绝对命令(例如 move by 10px, 2em
)、其他命令如 arc
,以及描述曲线控制点的各种方式。深入研究Web 标准以了解更多信息。当然,只要形状包含相同的命令列表,你就可以在形状之间进行动画,这可以产生一些非常酷的效果。
CodePen 上创作的 Pen – 形状动画
在CodePen上。
告诉我们您对 shape()
的看法。我们很想看看您会创造出什么!