CSS 怎么在图片中间画弧线:伪元素与 SVG 两种做法的取舍

编程狮(w3cschool.cn) 2026-10-22 07:06:46 浏览数 (26)
反馈

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

在图片中间画一条弧线的两种 CSS 做法

很多人第一次接到这个需求会下意识去找"画弧线的 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 路径两种画弧方式的结构对比

三、做法二: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 节点和一次路径栅格化,在几十张图的列表页里才需要留意。

延伸学习

想把这两种画弧做法练熟,可以按这个顺序来:

  1. 读一篇相关笔记 伪类和伪元素,把伪元素的定位与层叠关系看清;
  2. 想系统补一遍基础,CSS 入门课程 可以跟一遍;
  3. 想快速试圆角与弧度的数值,用 CSS3圆角生成器 生成后对照改。

0 人点赞