渐变圆环进度条的新思路,附上JS和Angular的实现

1,726 阅读4分钟

大家好我是创意行业中的前端prupru。

有一天设计师小哥哥突然丢给了我一张图,是一个倒计时的圆环

我们假装这个圆环的尾部是宽度不变颜色不变但是逐渐变淡变为背景色。

(气死我了就在我写好这篇文章的时候我发现设计师小哥又把需求改了我找不到原图了气死我了一时半会儿我也找不到一模一样的图而且我要出门了气死我了但是你们还是往下看吧)

需求解读

圆环尾部渐变(颜色变淡)

**这个问题可以抽象成:给到一个角度,如何绘制一个弧线(arc)? **

(划去:虽然第一眼不知道怎么做,但是这么常见的需求,我一定可以找到别人的代码复制一下

搜索大法

搜索了一下逐渐意识到事情不简单......

因为css或者svg没有直接给出绘制弧线的接口,所以我看到的目前主流思路有:

1. svg可以通过clipPath得到一个半圆。所以画2个半圆,在<180度的时候旋转第一个半圆,在>180度的时候显示第一个半圆,并旋转第二个半圆拼接成一段完整的弧线。

2. 数学几何大神路线:通过弧线公式计算路径,优点是高级,但是需要用javascript。 

重新定义问题

上述两种方法都优点不太直观?(遁走

我又看了看设计小哥的图,圆环渐变色融入不透明背景,觉得这次的需求可以取个巧:

不从形状入手,从渲染的颜色入手不就好了? 

问题重新定义为:如何根据角度,绘制一个锥形渐变? 

初步达成

锥形渐变和辐射渐变很容易被混淆。

(图来自 css-tricks.com/snippets/cs… 

左边是锥形渐变(颜色随着角度变化),右边是辐射状渐变(颜色随着半径长度变化)

锥形渐变css用法如下

.conic-gradient {
  background: conic-gradient(#fff, #000);
}

和其他的渐变一样,如果不指定颜色百分比的话就平均分布颜色,于是得到上方左边的图。

如果给第1个颜色加上一个百分比%,来决定渐变开始的位置。在这里第1个颜色是白色,第2个颜色是黑色。

.conic-gradient {
  background: conic-gradient(#fff 25%, #000);
}

于是渐变从90度才开始。0-90度都是第1个颜色。这不是我们想要的效果。

第二种尝试,给第2个颜色加上一个百分比%,来决定渐变结束的位置。在这里第二个颜色是黑色。

.conic-gradient {
  background: conic-gradient(#fff, #000 25%);
}

有点像了,我们成功地把渐变的范围缩小到了0-90度。但是0-90度是一个均匀的渐变,还是太散了。

第三种尝试,给2种颜色都加上百分比。

.conic-gradient {
  background: conic-gradient(#fff, #fff 20%, #000 25%);
}

对就是这种感觉,渐变被缩小到了一个范围,非常可控!

依葫芦画瓢

自己稍微对着需求改一下,在中心加上一个半径较小的圆用于遮挡,就有了

过于分散的建渐变(图片出自本人截图)

这就是对渐变不加控制的情况,不符合需求,视觉体验上对时间的流失感也不是很强。

假设时间过了一半,所以理想的渐变幅度是在180度的前后175~185度的地方产生由蓝到白的渐变,在185到360度的地方全部白色(即没有颜色)。

修改后得到如下

理想的渐变(图片出自本人截图)

Show you the code:

HTML

<div class="circle circle-container">
  <div class="circle circle--outer">
    <div class="circle circle--inner">
      <div class="text">60<span>s</span></div>
    </div>
  </div>
</div>

Javascript

let percentage = (totalSeconds - currentSecond) / totalSeconds * 100;

let background = 
  `conic-gradient(blue, blue ${percentage - margin}%, white ${percentage + margin}%)`;

outerCircle.style.background = background;

重点在于控制锥形渐变中颜色的位置百分比!

完整的demo和代码放在Codepen

codepen.io/Prudenceyyx…

Angular版本放在了这里

stackblitz.com/edit/ring-c…

和简易js版本的区别在于:

1. 虽然只是个小demo,但是在使用框架的时候尽量注意单一原则,即渲染组件和逻辑分离。这里的timer组件仅通过计算Input参数比如总时长、当前时长、容器和内圆的半径等等来渲染,倒计时的逻辑则放在了app组件或者其他组件。

2. MVC/MVVM框架尽量不人为操作DOM,所以在Angular中修改css的background属性(以及其他属性)的方式是通过指令向DOM元素传入background的字符串值,而不是直接查询元素。

参考:

1. conic-gradient() - CSS: Cascading Style Sheets | MDN

developer.mozilla.org/en-US/docs/…

2. CSS Conic Gradient | CSS-Tricks  

css-tricks.com/snippets/cs…

第一篇文章求个赞!

以及这里是我工作之外的个人成长/书单公众号【BackLog后台思考】