最近一段时间,业务上需要开发一个仪表盘页面,其中有个部分是圆弧进度条的效果,如下图所示:
其具体需求如下:
- 半圆形进度条,中间是进度数字,圆弧渐变背景表示进度,从 0% 到 100%
- 20%进度以下绿色渐变,20%~80% 蓝色渐变,80% 以上橙色渐变
首先写一个函数,根据进度设置渐变色值:
js
// 根据比例范围,设置渐变弧形进度条的两端色值
function getColor(percent: number) {
if (percent >= 80) return ['#FC8D2A', '#FC5618']
if (percent >= 20) return ['#179AF5', '#0F51FD']
return ['#24D32D', '#1CAA0D']
}
然后开始做半圆形进度条组件,以 React 为例,组件实现如下(Vue 的实现是类似的):
js
function CircleProgress({ percent }) {
const [start, end] = getColor(percent)
const deg = 1.8 * percent
const background = `conic-gradient(from -90deg at bottom, ${start} 0deg, ${end} ${deg}deg, #e8ebee ${deg}deg)`
return (
<div className="circle-progress-container" style={{ background }}>
<div className="circle-progress-inner">
<div className="status-number">{percent}%</div>
</div>
</div>
)
}
CSS 代码如下:
css
.circle-progress-container {
width: 100px;
height: 50px;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
position: relative;
transition-property: background;
transition-duration: 300ms;
transition-timing-function: ease;
}
.circle-progress-inner {
width: 80px;
height: 40px;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
background-color: #eff3fc;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
display: flex;
align-items: center;
justify-content: center;
}
.status-number {
margin-top: 5px;
font-weight: bold;
}
代码看起来非常简单,现对其实现进行拆解:
用 CSS 画半圆
用 CSS 如何画圆弧呢?有两种实现方式:
- 画一个半圆,然后设置 border
- 画两个半圆,然后设置 background
可以看到,这两种方式都要求先画半圆。那如何用 CSS 画半圆呢?首先在 HTML 里面定义一个类名为 container 的容器:
html
<div class="container"></div>
然后对其设置 CSS 样式:
css
.container {
width: 500px;
height: 250px;
box-sizing: border-box;
background-color: tomato;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
}
这样就能得到一个完美的半圆形了:
注意,这里面有两个关键点:
- 容器是一个矩形区域,且宽度是高度的两倍
- 左上角和右上角的弧形半径保持跟宽度一致
用 CSS 画圆弧
掌握了如何用 CSS 画半圆之后,接下来就开始画圆弧了,对上面说的两种方案都做了尝试:
方案一:为单个半圆设置 border
只要设置容器的 border,并且把 border-bottom 设置为空即可:
css
.container {
width: 500px;
height: 250px;
box-sizing: border-box;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
border: 25px solid tomato;
border-bottom: none;
}
注意这里的容器是矩形区域,而不是半圆,你可能会这样设置(我就犯了类似的错误):
css
.container {
width: 500px;
height: 250px;
box-sizing: border-box;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
border-top: 25px solid tomato;
}
这是不对的,因为会得到下面的图案:
但是当需要设置渐变色的时候,卡住了,CSS 并没有提供一个能够为 border 设置渐变色的 API,唯一可以在 border 上做定制的是 border-image
属性,例如:
css
.container {
width: 500px;
height: 250px;
box-sizing: border-box;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
border: 25px solid tomato;
border-bottom: none;
border-image-source: linear-gradient(to right, tomato, blue);
border-image-slice: 1;
}
然而非常遗憾的是,border-image
无法配合 border-radius
一起使用,最终得到的效果如下:
虽然渐变有了但圆角没了,也就是说,无法在半圆的边框上设置渐变色,于是这种方案只能被弃用了。
方案二:为两个半圆分别设置 background
首先需要嵌套的 DOM 结构,设置外层和内层两个半圆::
html
<!-- 外层半圆 -->
<div className="circle-progress-container">
<!-- 内层半圆 -->
<div className="circle-progress-inner"></div>
</div>
外层半圆的样式:
css
.circle-progress-container {
width: 100px;
height: 50px;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
position: relative;
background: tomato; /* 外层半圆背景色 */
}
内层半圆的样式:
css
.circle-progress-inner {
width: 80px;
height: 40px;
border-top-left-radius: 50% 100%;
border-top-right-radius: 50% 100%;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
background: white; /* 内层半圆背景色 */
}
注意这里:
为了确保外层半圆和内层半圆的圆心重叠,需要设置外层半圆的定位为相对定位,内层为绝对定位并居中。
接下来的关键就是如何设置渐变色了,由于圆环的颜色是外层半圆的背景色,CSS 提供了一个 cornic-gradient
属性,可以用于设置环形渐变,例如下面的代码:
css
background: conic-gradient(red, orange, yellow, green, blue);
得到的效果就是以圆心为中心,向四周扩散的渐变效果,大家可以在 MDN 文档中进行体验:
注意,cornic-gradient
的效果和 radical-gradient
是不一样的,容易搞混淆。前者是从圆心向任意方向射出的直线上的颜色都一样,而后者是跟圆心距离相同的圆环上的颜色都一样:
因此,只需要拿到渐变两端的颜色,对 CSS 值进行拼接即可:
js
const [start, end] = getColor(percent)
const deg = 1.8 * percent
const background = `conic-gradient(from -90deg at bottom, ${start} 0deg, ${end} ${deg}deg, #e8ebee ${deg}deg)`
这里把内层半圆去掉,可以更清楚的看到 cornic-gradient
实现的渐变效果:
内层半圆添加上背景色,就完美实现了开头的弧形渐变。
总结
阅读本文,可以掌握以下知识点:
- 如何用 CSS 画一个半圆
- 如何用 CSS 画一个纯色圆弧
- 如何用
cornic-gradient
画渐变背景 - 如何用 CSS 画一个渐变色圆弧