先给结论:只是想让图片中间出现一条弧线做装饰,用伪元素配 border-radius 画一个超宽的大圆压在图上最省事;如果弧线的弧度、位置要精确可调,还要跟着图片一起等比缩放,就改用 SVG 画一条 path。真要把图片本身裁出弧形边界,那是 clip-path 的活。

很多人第一次接到这个需求会下意识去找"画弧线的 CSS 属性",结果找不到。因为 CSS 里没有弧线这个图元,弧线都是"借"出来的:借圆的边、借 SVG 的路径、借裁切区域的边界。借法不同,代价也不同——圆的边不好调弧度,SVG 要多写一个元素,裁切会真的把图切掉一块。
本文给一个固定的最小场景,两种做法都给出能直接跑的完整代码,讲清各自的适用边界与失败分支,最后用一张对照表收尾。示例不依赖任何框架。
先看结论
- 弧线只是装饰、位置固定:伪元素加 border-radius,零额外元素,改一个宽度值就能换弧度。
- 弧度要精确、要随图缩放:SVG 的 path 写一条二次贝塞尔曲线,坐标和图片同比例。
- 要裁掉图的一部分而不是画线:用 clip-path 配 path 或 ellipse,注意它会真的改变可见区域。
属性细节记不清时,翻 CSS 教程 里按属性分组的清单最快。
一、最小场景与预期行为
任务定死:一张 600 像素宽、400 像素高的图片,在垂直中线位置画一条向下弯的弧线,弧的最低点比两端低 60 像素,弧线上方保持原图,下方盖一层半透明遮罩。
输入是一段 HTML 加 CSS。预期行为有三个:弧线位置在中线附近、缩放图片时弧线跟着走、弧的边缘不出现锯齿。
<div class="photo">
<img src="cover.jpg" alt="示例图片">
</div>
.photo {
position: relative;
width: 600px;
overflow: hidden;
}
.photo img {
display: block;
width: 100%;
}
这段做的是给图片套一层定位容器,并裁掉溢出的部分。两种做法都建立在这个结构上,区别只在怎么"借"出那条弧。
二、做法一:伪元素配 border-radius
思路是画一个宽度远超容器的圆,只让它顶部的那一段边露在图片中间,视觉上就是一条弧线。
.photo::after {
content: "";
position: absolute;
left: 50%;
top: 40%;
width: 200%;
aspect-ratio: 1;
transform: translateX(-50%);
border-radius: 50%;
background: rgba(254, 106, 0, .35);
box-shadow: 0 -2px 0 #fe6a00;
}
这段做的是:用 aspect-ratio 保证伪元素是正圆,宽度设成容器的两倍,再往左移自身一半居中。圆的上边缘在图片中形成一条向上凸的弧,box-shadow 那条橙色线就是弧线本身。
两个数值决定弧度:宽度越大弧越平缓,top 值决定弧线落在哪个高度。想让弧度更弯,把 200% 调小到 120%;想让弧更平,调到 300% 甚至更大。
这个写法的优点是零额外标签、改两个数就能调,性能上只是一个合成层。缺点是弧度没法精确描述——你只能说"差不多这么弯",没法说"最低点比两端低 60 像素"。

三、做法二:SVG path 画一条可度量的弧
要精确,就把弧交给 SVG。SVG 里画弧用的是路径命令,二次贝塞尔曲线一条命令就够。
<div class="photo">
<img src="cover.jpg" alt="示例图片">
<svg class="arc" viewBox="0 0 600 400" preserveAspectRatio="none">
<path d="M0 200 Q300 320 600 200" fill="none"
stroke="#fe6a00" stroke-width="4"></path>
</svg>
</div>
.arc {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
这段做的是:SVG 的 viewBox 与图片同比例,路径从左边中点 (0,200) 出发,用控制点 (300,320) 拉出向下的弧度,到右边中点 (600,200) 结束。控制点的 y 值越大弧越深,改 320 这个数字就能精确控制最低点。
这里有个关键取舍:preserveAspectRatio 写成 none 会让弧线随容器拉伸,图片和弧线始终贴合;但拉伸会让描边宽度变形。想保持线宽一致,就去掉这个属性,代价是弧线不再严格贴合非等比缩放的容器。
真正要"切掉"图片一部分时,才轮到 clip-path。下面这段会把弧线以下的区域整体裁掉:
.photo img {
clip-path: path("M0 0 H600 V200 Q300 320 0 200 Z");
}
这段做的是用一条闭合路径描述保留区域。注意 path 函数里的坐标是像素值,不会随容器缩放,图片尺寸变了要同步改。这个限制决定了 clip-path 的适用场景:固定尺寸的装饰图可以,响应式大图不建议。
四、常见失败分支与验证清单
4.1 弧线变成了椭圆的一段
伪元素没有保证宽高相等就会画成椭圆。修复办法是加 aspect-ratio: 1,或者显式写死 height。
4.2 弧线被 overflow 裁没了
父容器写了 overflow: hidden,超宽的伪元素被裁掉一半。修复办法是把圆的位置往下挪,让需要露出的那段边落在容器内部。
4.3 图片换了尺寸弧线就错位
SVG 方案里 viewBox 与图片实际比例不一致导致。修复办法是让 viewBox 与图片原始宽高一致,并在容器上约束 aspect-ratio。
4.4 验证清单
- 检查:伪元素的 computed 面板里 width 与 height 是否相等
- 运行:把容器宽度从 600 像素改到 300 像素,观察弧线是否仍在中间
- 预期:SVG 方案弧线等比缩小;伪元素方案弧度会变平缓
- 失败:弧线完全消失 → 伪元素被裁切或层级被图片盖住
- 修复:给伪元素加 z-index,或调整 top 值让弧落在可视区域内
- 验证:在两个不同宽度的容器里各看一次,确认弧线端点贴住左右边缘
上面这些步骤做的是确认弧度、跑通缩放、比对两种方案的边界差异。预期结果(未在本机执行)是 SVG 方案在缩放后仍然贴合;若两端出现缝隙,多半是 viewBox 与图片比例不一致。

总结
图片中间画弧线没有现成属性,靠的是"借":伪元素借圆的边,SVG 借路径,clip-path 借裁切边界。装饰性、位置固定的弧用伪元素最快;要精确度量、要随图缩放的弧用 SVG;只有真要切掉图像内容时才用 clip-path。
三条要点带走:
- 伪元素方案的关键是两个数:圆的宽度决定弧度,top 决定位置;
- SVG 方案的关键是控制点,viewBox 必须与图片同比例;
- clip-path 的 path 用像素坐标,响应式场景下要慎用。
下一步建议把这两种做法封装成一个接受"弧度深浅"参数的组件,内部选哪种实现对调用方透明。需要更多图形技巧时,Css Secrets 教程 里有成体系的实战案例。
常见问题
Q:为什么我画的弧线看起来是椭圆不是圆弧?
A:伪元素宽高不相等导致的。加 aspect-ratio: 1 或写死 height,让元素保持正方形,border-radius: 50% 才会画出正圆。
Q:SVG 画的弧线在窄屏上变形了怎么办?
A:去掉 preserveAspectRatio="none",让 SVG 按原比例缩放。代价是弧线不再严格贴合被拉伸的容器,需要同时约束容器的 aspect-ratio。
Q:clip-path 的 path 能不能用百分比?
A:clip-path 的 path 函数只接受像素坐标,不随容器缩放。响应式场景下改用 SVG 方案,或者换 ellipse、polygon 这些支持百分比的形状函数。
Q:弧线被图片盖住了怎么修?
A:伪元素默认在图片之后绘制但仍可能被覆盖。给伪元素显式加 z-index: 1,并确保父容器有定位上下文。
Q:两种做法在性能上有区别吗?
A:伪元素只多一个合成层,代价最小。SVG 多一个 DOM 节点和一次路径栅格化,在几十张图的列表页里才需要留意。
延伸学习
想把这两种画弧做法练熟,可以按这个顺序来:

TRAE-AI编程



