• CSS动效集锦,视觉魔法的碰撞与融合(三)


    本文讲述的原理和相关demo
    • 扇形DIV的使用——实现雷达扫描图
    • DIV环形布局—实现loading圈
    • 动画的向量合成—实现抛物线动画
    • 无限滚动动画—实现跑马灯效果
    • perspective和transform的运用——实现卡片翻转
     
    话不多说,请看。
     

    扇形DIV的使用——实现雷达扫描图

    在一些杀毒或文件扫描类的软件上,我们可能会看到一些雷达扫描的UI样式,例如下图所示
     
    如果我们要通过CSS该如何去实现话,我们的想法一般是先画个扇形,然后给它加上渐变。
    实现渐变的方式很简单,但我们该如何实现一个扇形呢?
     
    我们可以通过一些技巧实现这一点,请看:
    没错,我们可以通过skew函数,将黄色的div倾斜,然后溢出部分通过overflow:hidden遮住就可以了。
    • 锐角扇形:deg<0,向右边倾斜,即可得到锐角扇形
    • 钝角扇形:deg>0, 向左边倾斜,即可得到钝角扇形
     
    代码如下
    // CSS代码
    @keyframes rotateAnimate {
      from {
        transform: rotate(0deg) skew(-30deg)
      }
     
      to {
        transform: rotate(360deg) skew(-30deg)
      }
    }
     
    .fan-wrapper {
      overflow: hidden;
      position: relative;
      margin: 100px;
      width: 200px;
      height: 200px;
      border-radius: 50%;
      background: red;
    }
     
    .fan {
      position: absolute;
      right: 0;
      animation: rotateAnimate 2s linear infinite;
      /* 这一行很重要,设置左下角为旋转点 */
      transform-origin: 0% 100%;
      width: 100px;
      height: 100px;
      background: blue;
    }
     // HTML代码    
     <div class="fan-wrapper">
      <div class="fan"></div>
    </div>
     
    实现效果如下图所示
    (因为篇幅有限,渐变就不加了2333)
     

    DIV环形布局—实现loading圈

     
    loading加载条是常见的一种UI组件,如下图所示
    而要实现它,就需要考虑怎么把一堆小圆等距地布局在一个“大圆”的边框上,也就是DIV的环形布局的问题。
    当然我们可以通过暴力测量解决,但很麻烦且不优雅,而且如果小圆的数量变化的话要重新测一遍。
    我的解决办法如下:
     
    第一步:根据圆的数量计算相邻圆和圆心形成的夹角
    例如假设我们需要排列8个圆,那么夹角为360度 / 8 = 45度。图示如下,每个数字代表以该位置为圆心放一个小圆
     
    第二步:以外部DIV左下角为原点,批量计算小圆圆心的横纵坐标
    批量算出所有圆的相对坐标,我们以编号8的圆为例,假设半径R和X轴的逆时针夹角为θ,则有以下等式
    (cos/sin可能有正负,而等式同样成立)
    第三步,外部div相对定位,内部小圆绝对定位,并且将步骤二中计算的X/Y作为小圆的bottom和left去设置
    这一步也是批量完成,下图以编号8的圆为例
     
    代码
    CSS/HTML代码如下:
    我们在一个父div内部放8个子div。父div相对定位,而子div绝对定位
    // CSS代码
    .circles {
      position: relative;
      margin: 50px;
      width: 200px;
      height: 200px;
    }
     
    .circle {
      position: absolute;
      width: 20px;
      height: 20px;
      border-radius: 50%;
      background: black;
    }
     // HTML
    <div class="circles">
      <div class="circle circle1"></div>
      <div class="circle circle2"></div>
      <div class="circle circle3"></div>
      <div class="circle circle4"></div>
      <div class="circle circle5"></div>
      <div class="circle circle6"></div>
      <div class="circle circle7"></div>
      <div class="circle circle8"></div>
    </div>
     
    JS代码如下
    第一步:编写calcXYs方法: 以外部DIV左下角为原点,批量计算小圆圆心的横纵坐标
    /**
     * R:大圆半径,2*R = 外部正方形的边长
     * r:在大圆边上等距排列的小圆的半径
     * counts: 圆的数量
     * 返回值:
     *  [
     *    [x1,y1],
     *    [x2,y2],
     *    ...
     *  ]
     */
    function calcXYs(R, r, counts) {
      // 当前度数
      let deg = 0;
      // 单位度数,两小圆和圆心的夹角
      const pDeg = 360 / counts;
      // 存放返回结果
      const arr = [];
      for (let i = 0; i < counts; i++) {
        // 度数以单位度数递增
        deg = pDeg * i;
        // Math.sin接收的参数以 π 为单位,需要根据360度 = 2π进行转化
        const proportion = Math.PI / 180;
        // 以外部DIV左下角为原点,计算小圆圆心的横纵坐标
        let Y = R + R * Math.sin(proportion * deg);
        let X = R + R * Math.cos(proportion * deg);
        // 存放结果
        arr.push([X, Y, deg]);
      }
      return arr;
    }
     
    第二步:编写resizeCircles方法: 根据上一步的结果:调整绝对定位的小圆的位置
    /**
     * R,r,counts:含义同上
     * selector: 获取所有小圆的标志符
     * 作用:根据上一步的坐标计算结果,调整绝对定位的小圆的位置
     */
    function resizeCircles(selector, R, r, counts) {
      // 获取所有小圆NodeList的选择器
      let list = document.querySelectorAll(selector);
      //调用calcXYs方法
      const XYs = calcXYs(R, r, counts);
      // 遍历每个小圆的XY坐标
      for (let i = 0; i < list.length; i++) {
        const [X, Y] = XYs[i];
        const e = list[i];
        // 修改小圆距离外部DIV底部和左边的距离
        e.style.left = X + "px";
        e.style.bottom = Y + "px";
      }
    }
     
    最后我们只需要调用resizeCircles方法就可以啦
    resizeCircles(".circle", 60, 20, 8);

     

    实现效果如下
     
    让loading图标动起来
    好,现在布局完成了,那我们该怎么去让这个loading图标“动起来”呢?
    1. 给每个圆设置animation实现明暗变化,例如可以设置黑色的背景色然后动态变化opacity
    2. animation属性可以设置delay实现动画延迟播放,我们依次给圆设置等距的delay,例如1s,2s,3s...
    3. 给animation属性设置alternate,表示往复播放,设置infinite,表示无限循环播放
     
    @keyframes k {
      from {
        opacity: 1;
      }
     
      to {
        opacity: 0;
      }
    }
    .circle1 {
      animation: k 1s ease 0s alternate infinite;
    }
     
    .circle2 {
      animation: k 1s ease 0.2s alternate infinite;
    }
     
    .circle3 {
      animation: k 1s ease 0.4s alternate infinite;
    }
    // circle4 ~ circle8同理,delay以0.2s递增
     
    Demo
     

    动画的向量合成—实现抛物线动画

     
    在饿了么,或者淘宝天猫之类的购物外卖相关的APP里,我们可能会看到类似于下面这种的抛物线的动画。
     
    如果要实现这种平抛效果,需要一点基础的高中物理知识。
    平抛运动由水平方向的两种运动合成而得到
    • 水平方向: 匀速直线运动
    • 垂直方向:初速度为0的匀加速直线运动
    如下所示
     
    如果我们通过图像捕捉的方式就可理解的更清楚了,从下面的图可以看到:
    水平方向的速度是不变的,而垂直方向的速度是不断加快的
    好,下面终于可以讲下CSS的实现思路了
    CSS实现原理
    1. 设置两个div:外层div和内层div
    2. 外层div设置横向匀速运动的动画
    3. 内层div设置纵向的匀加速直线运动的动画,加速过程可以用cubic-bezier设置
     
    cubic-bezier又叫做贝塞尔曲线,它可接收四个参数,来规定动画的速度变化过程,使用方法如下
    transition-timing-function: cubic-bezier(0.1, 0.7, 1.0, 0.1);
     
    我们可以通过下面这个官方网站去设置速度变化曲线,然后获取生成的四个参数
     
    具体代码如下:
     // HTML
    <div id="outer">
      <div id="inner"></div>
    </div>
    <button id='btn'>抛物线效果</button>
    // CSS #outer
    { transition: all 1.5s linear; } #inner { width: 30px; height: 30px; border-radius: 50%; background: red; transition: all 1.5s cubic-bezier(.54, .11, .95, .68); } .outer-active { transform: translateX(300px); } .inner-active { transform: translateY(300px) scale(0.3); }
    JS
    document.getElementById("btn").onclick = function() {
      document.getElementById("outer").classList.add("outer-active");
      document.getElementById("inner").classList.add("inner-active");
    };
     
    效果如下
     
     
     

    无限滚动动画—实现跑马灯效果

    当文本过长时候,我们可能需要做成跑马灯效果,然后无限滚动播放。
     
    因为marquee这个HTML元素被废弃了,所以一般情况下我们需要手动通过动画去实现跑马灯
    实现图示如下,注意开始位置和结束位置是不可见的
     
    // HTML
    <div class="marquee">
      <p>ABCDEFGHIJKLMN</p>
    </div>
    // CSS
    @keyframes marquee {
      from {
        transform: translateX(-200px)
      }
     
      to {
        transform: translateX(200px)
      }
    }
     
    .marquee {
      overflow: hidden;
      margin: 100px;
       200px;
    }
     
    .marquee p {
      animation: marquee 3s linear infinite;
    }
     
    结果
     
     

    perspective和transform的运用——实现卡片翻转

    卡片翻转三要素
    • transform: rotateY(x deg) 翻转卡片
    • backface-visibility:hidden 翻转后隐藏背面,重要!必须要加
    • perspective:增加透视和立体效果
     
    // HTML
    <div id="img-wrapper">
      <img src='./timg.jpg' id='img1' class="img disable-img1" />
      <img src='./timg2.jpg' id='img2' class="img" />
    </div>
     
    // CSS
    #img-wrapper {
      perspective: 1200px;
      position: relative;
      height: 479px;
    }
     
    #img1,
    #img2 {
      position: absolute;
      transition: all 1s linear;
      backface-visibility: hidden;
    }
     
    #img1 {
      transform: rotateY(-180deg);
    }
     
    #img-wrapper:hover #img1 {
      transform: rotateY(-360deg);
    }
     
    #img-wrapper:hover #img2 {
      transform: rotateY(-180deg);
    }
     
    结果
     
  • 相关阅读:
    第六次学习笔记
    第四篇笔记
    第三篇学习笔记
    第二篇学习笔记
    第一篇学习笔记
    px与dp、sp之间的转换
    SQLite的使用(二):数据增删改查
    Logcat的级别以及Logcat的调试使用
    Android 创建服务(一)
    简说SQLite
  • 原文地址:https://www.cnblogs.com/penghuwan/p/12239817.html
Copyright © 2020-2023  润新知