• 用css动态实现圆环百分比分配——初探css3动画


    最近的小程序项目有个设计图要求做一个圆环,两种颜色分配,分别代表可用金额和冻结金额。要是就直接这么显示,感觉好像挺没水平??于是我决定做个动态!

    在mdn把新特性gradients(渐变)、transitions(过渡)、 animations(动画) 都看了一遍,不禁感叹css牛逼!这三个新特性加上canvas,仿佛一瞬间有了正面刚js的能耐。用js很难过渡得那么完美,而且浏览器的css渲染明显比用js性能好得多。
    然后看了张鑫旭(传说中玩转css的那个男人)的一篇关于圆环的博文,拍案叫绝。链接=>3种纯CSS实现中间镂空的12色彩虹渐变圆环方法
    只能说服气!除了灵活运用各种css特性之外,鑫大佬最让我佩服的是他的创造性思维。会让你不禁感叹:卧槽,还有这种操作?!想到了高中物理老师每次装完逼讲的一句话:思想有多远,就能走多远。

    虽然demo跟我的需求不太一样,问题还是没有解决,但我认真看完之后还是学会了很多,对我后面的代码帮助很大。鑫大佬这篇博文的重点还是在渐变,而我需要动态平缓连续得实现颜色的分配,比如原本整个环是绿色,然后慢慢地60%被红色占了,而且整个过程要平滑。跟我的需求最接近的就是倒计时那个demo,linear-gradient线性渐变实现的多彩圆环demo,但不是连续的过程,而是通过剪裁,每次剪30度。

    看了其他一些博客分享,好像也没有找到合适的,那没办法了...只能自己想一个!
    因为再写这个demo的时候,发现小程序和H5在css表现上还是有些差异(具体有哪些差异,在文末总结),所以还是贴H5代码好了。

    不多说,直接上代码


    代码部分

    //html部分
    <div class="circle">
      <div class="circle-left"></div>
      <div class="circle-right"></div>
      <div class="circle-bottom-left"></div>
      <div class="circle-bottom-right"></div>
    </div>
    <div class="info">¥4500/¥5000</div>
    //css部分
    .circle {
      -webkit-mask: radial-gradient(transparent 150px, #000 150px);
       400px;
      height: 400px;
      overflow: hidden;
      border-radius: 50%;
      position: relative;
    }
    
    .circle-left {
       50%;
      height: 100%;
      background: #24B39B;
      transform-origin: 100% 50%;
      position: absolute;
      left: 0;
      z-index: 0;
    }
    
    .circle-right {
       50%;
      height: 100%;
      background: #24B39B;
      transition: transform 1s linear;
      transform-origin: 0% 50%;
      position: absolute;
      right: 0;
      z-index: 2;
    }
    
    .circle-bottom-left {
       50%;
      height: 100%;
      background: rgb(234, 67, 15);
      position: absolute;
      left: 0;
      z-index: -1;
    }
    
    .circle-bottom-right {
       50%;
      height: 100%;
      background: rgb(234, 67, 15);
      position: absolute;
      right: 0;
      z-index: 1;
    }
    
    .info {
       400px;
      height: 400px;
      line-height: 400px;
      text-align: center;
      margin-top: -400px;  
    }
    //js代码
    window.onload = function () {
      var red = 4500, total = 5000 //红色区域代表的金额和总金额
      var percent = red / total
      var right = document.getElementsByClassName('circle-right')[0]
      var left = document.getElementsByClassName('circle-left')[0]
      if (percent <= 0.5) {  //红色区域不超过一半
        right.style.transform = `rotate(${percent * 360}deg)`
      } else {    //红色区域超过一半的情况,重点部分
        right.style.transform = `rotate(180deg)`
        right.style.transition = `opacity 0s step-end 1s, transform 1s linear` //timing-function需要设为linear来达到视觉上的平缓过渡
        right.style.opacity = 0
    
        left.style.transition = `transform ${(percent - 0.5) / 0.5}s linear 1s`
        left.style.transform = `rotate(${percent * 360 - 180}deg)`
      }
    }

    效果图
    图片描述

    思路

    st=>start: 开始
    e=>end: 结束
    con=>condition: degree<=180?
    op1=>operation: 右绿旋转
    op2=>operation: 右绿旋转180度,opacity变为0,然后左绿旋转
    
    st->con
    con(yes)->op1->e
    con(no)->op2->e

    难点在于红色区域大于一半的情况,左右绿色半圆的衔接,过渡要自然,不能让人看出什么明显的破绽。
    **这种情况我的做法是:4个半圆(红绿各两个)的z-index设为左红<左绿<右红<右绿
    两个绿半圆的transform的time-function(时间函数)统一设为linear(线性)。右绿旋转180度(1秒)后opacity立即变成0(时间函数step-end),这样就不会挡住左红露出。然后左绿开始转(transform延迟1秒执行,因为要等待右绿转完),它转的时间要根据度数动态控制,比如总共要转270度,右绿转了180度,所以左绿只需要转90度。这就好办了,为了保持右绿的旋转速度,时间和度数要成比例,右绿转180度用1s,左绿转90度只能用0.5s

    优点

    1. 不需要js代码动态实现动画(js只用来计算度数和触发transition)
    2. 因为对js几乎没什么依赖,浏览器内核直接渲染,性能较好,过渡自然
    3. 代码量很少
    

    不足

    1. 因为是css3的属性,兼容不会太好
    2. 时间函数只能用线性linear,用默认的ease(不匀速)会衔接不上
    3. 只能两种颜色分布,再加一种的话行不通
    

    有更好办法实现相同效果的大佬,欢迎留言!

    问题探究&解决

    虽然效果图gif画质有点感人,但还是可以发现一个问题:内环边缘明显很粗糙!这个要怎么解决呢?
    中间这个透明遮罩的代码是`-webkit-mask: radial-gradient(transparent 150px, #000 150px);
    我的做法就是把transparent 150px改成transparent 148px,就是说空出一两个像素点,让粗糙的部分虚化。
    至于为什么会出现粗糙,额。。。我觉得是150px这一层上了太多颜色,加上本来画弧圈就没有防锯齿处理,色素点可能会拥挤,加剧了锯齿状这种效果。具体是什么原因,或者有更好的解决办法,欢迎大佬指教。

    修改后的效果图
    图片描述
    是不是明显好很多~

    上文提到的小程序的css和h5的差异,经过再一次的实验,发现不是小程序内核渲染的问题,应该是微信开发者工具显示的问题。。。希望尽快能得到改善,不然对开发人员影响挺大的

    clipboard.png这个info的盒子margin-top负数在工具中显示翻不上去,但内容50000上去了.
    clipboard.png过了几秒再点(啥都没干),这个info的盒子又跑到这里来

    clipboard.png为了验证这个info的盒子到底有没有上去,我加了一个红色的盒子,发现并没有被info盒子挤掉

    clipboard.png取消info的margin-top属性,红色的盒子被挤掉,内容50000也下来了

    终于!!!原来都是开发者工具摆的乌龙,其实info盒子一直在上面,只是调试不能正常显示他的位置。。。

    话说回来,小程序不能获取DOM节点操作DOM,突然觉得只能数据驱动,不能操作DOM节点有时也挺麻烦的,transition那些需要动态改的样式只能写到style了。。。

    最后,看好小程序,希望各种问题能尽快完善,越来越好。

  • 相关阅读:
    mybatis新增insert返回主键id,与解决新增主键id一直为1的问题。
    Mysql SQL语句查询今天、昨天、N天内、第N天的数据
    记录实时问题:java 出现unreachable statement异常
    java代码读取properties配置文件实例
    java设计模式详解
    java自用代码(包括:新建单线程、创建文件夹及文件、map转为json并将json写入txt、文件剪切或改名)
    ssm框架之持久层mybatis动态sql标签属性大全
    从onclick到function到ajax的url问号传多个参数(更多的话以此类推)问题
    TortoiseGit右击不显示图标或不显示状态图标等处理方法(win10、win7)
    Delphi 在写Ini文件时报错,Access violation at address 774D6EC8 in module 'ntdll.dll' write of address 004044CD
  • 原文地址:https://www.cnblogs.com/10manongit/p/12701911.html
Copyright © 2020-2023  润新知