CSS 实现渐变圆弧进度条

最近一段时间,业务上需要开发一个仪表盘页面,其中有个部分是圆弧进度条的效果,如下图所示:

其具体需求如下:

  • 半圆形进度条,中间是进度数字,圆弧渐变背景表示进度,从 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 画一个渐变色圆弧
相关推荐
清风细雨_林木木20 分钟前
解决 Tailwind CSS 代码冗余问题
前端·css
三天不学习44 分钟前
VueUse/Core:提升Vue开发效率的实用工具库
前端·javascript·vue.js·vueuse
余道各努力,千里自同风1 小时前
CSS实现文本自动平衡text-wrap: balance
前端·css
Yvonne爱编码1 小时前
CSS- 4.3 绝对定位(position: absolute)&学校官网导航栏实例
前端·css·html·html5·hbuilder
繁依Fanyi2 小时前
ImgShrink:摄影暗房里的在线图片压缩工具开发记
开发语言·前端·codebuddy首席试玩官
卓律涤2 小时前
【找工作系列①】【大四毕业】【复习】巩固JavaScript,了解ES6。
开发语言·前端·javascript·笔记·程序人生·职场和发展·es6
Ten peaches3 小时前
Selenium-Java版(环境安装)
java·前端·selenium·自动化
心.c3 小时前
vue3大事件项目
前端·javascript·vue.js
姜 萌@cnblogs3 小时前
【实战】深入浅出 Rust 并发:RwLock 与 Mutex 在 Tauri 项目中的实践
前端·ai·rust·tauri
蓝天白云下遛狗3 小时前
google-Chrome常用插件
前端·chrome