• 讲解 CSS 过渡和动画 — transition/animation (很全面)


    前言

    由于用户越来越注重 Web应用 的使用体验,随之而来的是 Web应用 需要提供了更加完善的 Web 动画 效果来实现以平滑的状态贯穿于用户的整个使用过程中。现在,这已经是司空见惯了,用户潜意识是希望可以获得更快的反馈响应和更友好的用户界面。

    什么是 Web 动画

    • 屏幕刷新率 设备显示器每秒绘制新图像的次数,其单位为赫兹 (Hz)。目前大多数设备为 60Hz。
    • 卡顿 每个帧的预算时间仅比 16毫秒 多一点(1秒/ 60 = 16.6毫秒)。如果浏览器无法在这一帧内完成工作,则帧率将下降,可能导致跳帧,内容会在屏幕上抖动。此现象通常称为卡顿。
    • 跳帧 假如浏览器动画分别在 16ms, 32ms, 48ms时分别切帧。等到了 32ms,浏览器其他任务还未完成,没有执行动画切帧。等到恢复动画切帧时,浏览器到了 48ms 的动画切帧。浏览器直接从16ms 处的画面 跳转到 48ms 处的画面,则发生了跳帧。

    在了解了上述几个概念后,我们再看 Web 动画本质是元素的外观样式或布局位置随着浏览器的逐帧绘制,以平滑的状态完成变化

    简述 JS / CSS 动画

    目前浏览器实现动画的方式有如下两种,本篇将主要讲解第二种 CSS 动画

    • JS 动画

      • setTimeout / setInterval / requestAnimationFrame
        我们最常用的是 setTimeoutsetInterval 这两个API。但是这两个 API 设定的时间会因为浏览器当前工作负载而有所偏差,而且无法与浏览器的绘制帧保持同步。所以才有了 与浏览器的绘制帧同步 的原生 API requestAnimationFrame,以取代 setTimeoutsetInterval 实现动画。
      • Animation API
        浏览器动画引擎 API,通过 JavaScript 操作。这些 API 被设计成 CSS TransitionCSS Animation 的接口,所以可以很容易通过 JS 的方式实现 CSS 动画,它是对动画化的支持最有效的方式之一。
    • CSS 动画 (本篇主题)

      • CSS Transition
        CSS 过渡,属于补间动画,即设置关键帧的初始状态,然后在另一个关键帧改变这个状态,比如大小、颜色、透明度等,浏览器将自动根据二者之间帧的值创建的动画。
      • CSS Animation
        CSS 动画,可以理解是 CSS Transition 的加强版,它既可以实现 补间动画 的动画效果,也可以使其以 逐帧动画 的方式进行绘制。

    学习 CSS 过渡 - transition

    就如之前所说,它属于 补间动画,需要提供起始和结束两个关键帧,浏览器才能够完成样式差异比对并计算出对应的过渡动画。所以它有两个特点:

    1. 由于首次渲染元素的样式只会有一个关键帧,浏览器无法进行样式差异比对,所以在首屏渲染时 transition 一般不会生效
    2. 由于浏览器是根据样式差异化的两帧自动计算并过渡,所以 transition 只支持可识别中间值的属性 (如大小、颜色、位置、透明度等),而如 display 属性则不支持。

    语法定义

    CSS 过渡通常使用简写属性 transition 来定义,这是最好的方式。既可以避免属性值列表长度不一,也节省了在 CSS 代码上调试的时间。当然也可以用下面子属性来定义过渡的各部分:

    • transition-property: 指定哪个或哪些 CSS 属性用于过渡。只有指定的属性才会在过渡中发生动画,其他属性仍如通常那样瞬间变化。

    • transition-duration: 指定过渡的时长。你可以为所有属性指定一个值,或者指定多个值,或者为每个属性指定不同的时长。

    • transition-timing-function: 指定一个缓动函数,定义属性值怎么变化。常见的缓动函数是一个三次贝塞尔曲线 ( cubic-bezier(, , , ) )。当然也可以选择关键字

      • linearcubic-bezier(0.0, 0.0, 1.0, 1.0)
      • easecubic-bezier(0.25, 0.1, 0.25, 1.0)
      • ease-incubic-bezier(0.42, 0.0, 1.0, 1.0)
      • ease-outcubic-bezier(0.0, 0.0, 0.58, 1.0)
      • ease-in-outcubic-bezier(0.42, 0.0, 0.58, 1.0)

      在这里插入图片描述

    • transition-delay: 指定延迟,即属性开始变化时与过渡开始发生时之间的时长。

      /* 单条 简写形式 */
      transition: 
           ;
      
      
      /* 多条 简写形式 */
      transition: 
           ,
           ,
        ...;
    
    
      /* 单条 子属性形式 */
      transition-property: ;
      transition-duration: ;
      transition-timing-function: ;
      transition-delay: ;
      
      
      /* 多条 子属性形式 */
      transition-property:  [, , ...];
      transition-duration:  [, , ...];
      transition-timing-function: [, , ...];
      transition-delay: [, , ...];
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    语法范例

    • 简写形式书声明过渡样式
      div {
        opacity: 1;
      }
      
      div:hover {
        opacity: 0.5;
        transition: opacity, 3s;
      }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 如果任意属性值列表的长度比其他属性值列表要短,则其中的值会重复使用以便匹配
      div:hover {
        transition-property: opacity, left, top, height;
        transition-duration: 3s, 5s;
      }
      
      /* 等同于下面样式声明 */
      
      div:hover {
        transition-property: opacity, left, top, height;
        transition-duration: 3s, 5s, 3s, 5s;
      }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 如果某个属性的值列表长于 transition-property 的属性,则将被截短
      div:hover { 
        transition-property: opacity, left;
        transition-duration: 3s, 5s, 2s, 1s; 
      }
      
      /* 等同于下面样式声明 */
      
      div:hover {
        transition-property: opacity, left;
        transition-duration: 3s, 5s; 
      }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    JS 相关事件监听

    你可以监听 CSS 过渡的开始和结束

    • transitionrun: CSS 过渡动画触发 (在任何延迟之前)
    • transitionstart: CSS 过渡动画触发 (在任何延迟之后)
    • transitionend: CSS 过渡动画结束

    事件监听回调函数会接收一个 TransitionEvent 对象,除了具有一般的 Event 对象外,还有两个额外属性:

    1. propertyName 一个字符串,表示过渡完成的 CSS 属性的名称。
    2. elapsedTime 一个浮点数,表示在事件发生时,过渡已经运行了多少秒。

    学习 CSS 动画 - animation

    CSS Animation 才算是真正意义上的 CSS3 动画,它具备了对 关键帧和循环次数 的自定义能力。与 CSS Transition 相比较,有如下 CSS 过渡 所不具备的特性:

    1. CSS Animation 在实现像 CSS Transition 补间动画 效果时,还可以在起始帧和结束帧之间自定义中间帧,使得动画更加平滑过渡的同时,对动画有了更好的控制和自定义能力。
    2. CSS Animation 通过 animation-timing-function: steps() 属性实现了 CSS Transition 无法具备的 逐帧动画 效果
    3. CSS Animation 只要定义了结束帧 (即 @keyframes 中的 to),在首屏渲染时,它默认会以指定元素在动画开始时刻的样式作为起始关键帧,并结合 to 定义的结束关键帧和指定元素的 animation 其他参数来完成补间动画的计算和动画帧的绘制。

    语法定义

    创建 CSS 动画序列,需要使用 animation 属性或 其子属性 animation-*,该属性允许配置动画时间、时长以及其他动画细节,但该属性不能配置动画的实际表现,动画的实际表现是由 @keyframes 规则实现。

    - @keyframe

    使用关键帧,先创建一个带名称的 @keyframes 规则,以便后续使用 animation-name 属性将动画同其关键帧声明进行匹配。每个规则包含多个关键帧,也就是一段样式块语句,每个关键帧有一个百分比值作为名称,代表在动画进行中,在哪个阶段触发这个帧所包含的样式。

    css
    复制代码
      @keyframes slidein {
        from {
          transform: translateX(0%);
        }
    
        to {
          transform: translateX(100%);
        }
      }
    
      /* 等效于下面 @keyframes 规则的定义 */
    
      @keyframes slidein {
        0% {
          transform: translateX(0%);
        }
    
        100% {
          transform: translateX(100%);
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    注意事项:

    1. 如果多个关键帧使用同一个名称,以最后一次定义的为准 (不存在层叠样式情况下)
    2. 同一关键帧中的相同属性被重复定义,则以最后一次定义的属性为准。
    - animation-*

    CSS 动画通常使用 animation 属性来定义,它是 animation-nameanimation-duration, animation-timing-functionanimation-delayanimation-iteration-countanimation-directionanimation-fill-modeanimation-play-state 等一系列属性的简写形式。

    • animation-name:指定一个或多个 @keyframes 的名称,描述了要应用于元素的动画。多个 @keyframes 以逗号分隔的名称列表的形式指定。

    • animation-duration:设置动画完成一个动画周期所需的时间,需要指定单位,如 1s500ms

    • animation-delay:指定执行动画之前的等待时间。动画可以稍后开始、立即从开头开始、立即在动画中途播放 (如 -1s) 。其中 -1s 意思是动画立即从 1s 处开始。

    • animation-iteration-count:设置动画序列在停止前应播放的次数,有效值 0、正整数、正小数、无限循环 infinite

    • animation-direction:设置动画是正向播放 normal、反向播放 reverse、正向交替播放 alternate、反向交替播放 alternate-reverse

    • animation-play-state:设置动画是运行还是暂停,有效值 runningpaused

    • animation-fill-mode:设置 CSS 动画在执行之前和之后如何将样式应用于其目标,有效值如下:

      • none:当动画未执行时,动画将不会将任何样式应用于目标,而是已经赋予给该元素的 CSS 规则来显示该元素。这是默认值

      • both:动画将遵循 forwardsbackwards 的规则,从而在两个方向上扩展动画属性

      • forwards:目标将保留由执行期间遇到的最后一个关键帧计算值。最后关键帧取决于 animation-directionanimation-iteration-count

        animation-directionanimation-iteration-countlast keyframe
        normaleven or odd100%
        reverseeven or odd0%
        alternateeven0%
        alternateodd100%
        alternate-reverseeven100%
        alternate-reverseodd0%
      • backwards:动画将在应用于目标时立即应用第一个关键帧中定义的值,并在 delay 期间保留此值。第一个关键帧取决于 animation-direction 值:

        animation-directionfirst keyframe
        normal or alternate0%
        reverse or alternate-reverse100%
    • animation-timing-function:设置动画在每个周期的持续时间内如何进行,主要是如下两种函数:

      • cubic-bezier 三次贝塞尔曲线 ( cubic-bezier(, , , ) ),以实现 补间动画 效果。

        1. linearcubic-bezier(0.0, 0.0, 1.0, 1.0)
        2. easecubic-bezier(0.25, 0.1, 0.25, 1.0)
        3. ease-incubic-bezier(0.42, 0.0, 1.0, 1.0)
        4. ease-outcubic-bezier(0.0, 0.0, 0.58, 1.0)
        5. ease-in-outcubic-bezier(0.42, 0.0, 0.58, 1.0)
      • steps 是一个分段的阶跃函数,,以实现 逐帧动画。n 相当于单次动画的帧数,每帧动画的时间是均等的 (steps(n, )),其中 jumpterm 含义如下:

        1. jump-start:在起始位置阶跃,n=2 ⇒ 50% 100%; (100 / 2)
        2. jump-end:在结束位置阶跃, n=4 ⇒ 0% 25% 50% 75%; (100 / 4)
        3. jump-none:起止位置均无跳跃,n=5 ⇒ 0% 25% 50% 75% 100%; (100 / 4)
        4. jump-both:起止位置均有跳跃 n=3 ⇒ 25% 50% 75%; (100 / 4)
        5. start:等同 jump-start
        6. end:等同 jump-end
        7. step-start:等同 steps(1, jump-start)
        8. step-end:等同 steps(1, jump-end)

        steps 函数动画示意图如下(输入为时间进度,输出为动画进度)

        在这里插入图片描述

        在这里插入图片描述

      /* animation 声明样式顺序 */ 
      /* animation-duration */
      /* animation-easing-function */
      /* animation-delay */ 
      /* animation-iteration-count */
      /* animation-direction */
      /* animation-fill-mode */
      /* animation-play-state */
      /* animation-name */
      animation: 3s ease-in 1s 2 reverse both paused slidein; 
    
      
      /* animation - duration | easing-function | delay | name */
      animation: 3s linear 1s slidein;
      
      
      /* more animations - duration | easing-function | delay | name */
      animation: 3s linear slidein, 3s ease-out 5s slideout;
    
     
      /* animation-name */
      animation-name: none;
      animation-name: animate1;
      animation-name: animate1, animate2;
      
      
      /* animation-timing-function */
      animation-timing-function: ease;
      animation-timing-function: step-start;
      animation-timing-function: cubic-bezier(0.1, 0.7, 1, 0.1);
      animation-timing-function: ease, step-start, cubic-bezier(0.1, 0.7, 1, 0.1);
      
      
      /* ...... */
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    语法范例

    • 简写形式书声明动画样式
      p {
        animation: 3s infinite alternate slidein;
      }
      
      @keyframes slidein {
        0% {
          margin-left: 100%;
          width: 300%;
        }
        100% {
          margin-left: 0%;
          width: 100%;
        }
      }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 非简写形式书声明动画样式
      p {
        animation-duration: 3s;
        animation-name: slidein;
        animation-iteration-count: infinite;
        animation-direction: alternate;
      }
      
      @keyframes slidein {
        0% {
          margin-left: 100%;
          width: 300%;
        }
        100% {
          margin-left: 0%;
          width: 100%;
        }
      }
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    实验性新属性

    • animation-range:设置动画附件范围沿其时间轴的开始和结束。
    • animation-timeline:指定用于控制 CSS 动画进度的时间轴。
    • animation-composition:指定当多个动画同时影响同一属性时要使用的复合操作。

    JS 相关事件监听

    你可以监听 CSS 动画的开始和结束

    • animationstart
      事件会在 CSS 动画开始时触发。如果有 animation-delay 延时,事件会在延迟时效过后立即触发。为负数的延时时长会致使事件被触发时事件的 elapsedTime 属性值等于该时长的绝对值
    • animationiteration
      当 CSS 动画的迭代结束,另一个迭代开始时,将触发动画迭代事件。此事件不会与 animationend 事件同时发生
    • animationend
      动画结束事件在 CSS 动画完成时触发。如果在动画完成前中止了动画,例如将元素从 DOM 中移除,或将动画从元素上移除,该事件不会触发。
    • animationcancel
      这个事件在 CSS Animation 属性意外中断时派发出来 (换句话说,任何时候 animation 停止运行不会发出一个 animationend 事件)

    事件监听回调函数会接收一个 AnimationEvent 对象,除了具有一般的 Event 对象外,还有额外属性:

    1. animationName 一个字符串,表示过渡完成的 CSS 动画的名称。
    2. pseudoElement 一个字符串,如果动画作用于伪元素上,则该属性为伪元素名称
    3. elapsedTime 一个浮点数,表示在事件发生时,过渡已经运行了多少秒。

    完整项目附件:点此下载

  • 相关阅读:
    乔迁之喜!泛微软件园启用,欢迎新老朋友来坐坐
    【大数据技术】hdfs通过网页端不能删除文件时的解决方法
    heketi管理glusterfs,k8s基于glusterfs创建storageclass
    nuxt 路由 & 动态路由配置
    新手零基础自学Python,安装并配置环境+教程
    向毕业妥协系列之机器学习笔记:高级学习算法-神经网络(二)
    @PathVariable, @RequestBody, @Param使用场景? 为什么用它?
    Spring Cloud Alibaba【Nacos配置动态刷新、Nacos集群架构介绍 、Nacos的数据持久化、认识分布式流量防护 】(五)
    最受欢迎的编程语言排行榜
    Vue计算属性与监视属性
  • 原文地址:https://blog.csdn.net/CRMEB/article/details/133862594