花潮论坛

搜索
热搜: 活动 交友 discuz
查看: 21|回复: 2

CSS关键帧动画初步

[复制链接]
  • TA的每日心情
    奋斗
    2026-7-27 10:54
  • 签到天数: 1882 天

    [LV.Master]伴坛终老

    3289

    主题

    13万

    回帖

    29万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9

    花潮帅哥鼠牛虎兔龙蛇马羊猴鸡狗猪多彩人生星月交辉奔放热烈海样胸怀春风拂面火热情怀优雅迷人神秘浪漫相遇之美鹰傲苍穹花好月圆紫色情节飞龙在天王者至尊大将风范音画大师天籁妙音共看流星风雨同行我心永远幸福快乐喜乐安康侠骨柔肠心想事成开朗大方花潮管理

    发表于 2026-7-27 14:33 | 显示全部楼层 |阅读模式

    请马上登录,朋友们都在花潮里等着你哦:)

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x

    CSS关键帧动画由 @keyframes 创建一个自定义名称的动画序列,再由元素对应的选择器通过 animation 属性调用动画。

    一、创建CSS关键帧动画

    创建CSS关键帧动画用 @keyframes 实现,语法结构:

    @keyframes 名称 {
        时间节点1 { CSS属性 }
        时间节点2 { CSS属性 }
        时间节点N { CSS属性 }
    }

    @keyframes 创建的动画序列以一系列关键帧描述动画形态,包含时间节点动画数据。时间节点可以使用百分比或关键字 from 和 to 表示,动画数据则是任意支持关键帧动画的单个或多个CSS属性。试看:

    /* 方法一 :百分比 */
    @keyframes move {
        0% { left: 0px; top: 10px; }
        100% { left: 240px; top: 180px; }
    }
    
    /* 方法二 :关键字 */
    @keyframes move {
        from { left: 0px; top: 10px; }
        to { left: 240px; top: 180px; }
    }

    上述两种关键帧动画的设计等价,但方法一更易于扩展:在0%~100% 之间可以加入任意多个时间节点用以描述更多的关键帧。方法二适用于简易动画,它只关心两个时间节点即 0% 和 100% 的动画状态。

    很多时候元素用于关键帧动画的对应CSS属性已经设置了初始值,若此,关键帧动画开始的时间节点可以省略(特别是基于关键字方法):

    /* 元素定义了 left和 top 初始值 */
    .ball { position: absolute; left: 0px; top: 10px; }
    
    /* keyframes 关键帧动画可以省略 from 关键字属性 */
    @keyframes move {
        to { left: 240px; top: 180px; }
    }

    对于追求简洁代码需求而言,这是有效的方法,但一切应根据具体情况而定。

    二、运行CSS关键帧动画

    CSS关键帧动画由元素运行,通过元素对应CSS选择器的 animation 属性进行设置。animation 属性语法结构如下:

    /* 红色参数必须,其余可选(缺省时使用默认值) */
        animation: ①动画名称 ②周期时长 ③时间函数 ④延时时间 ⑤运行次数 ⑥运动方向 ⑦结束状态 ⑧播放状态
    /* 应用举例 :①move动画,②6秒一周期,③匀速,④延时0秒,⑤运行一次,⑥正向,⑦保留最后状态,⑧运行 */
    animation: move 6s linear 0s 1 normal forwards running;
    /* 因为 0s、normal、running 属性值都是默认值,可以简化为 */
    animation: move 6s linear 1 forwards;

    animation 是一个简写属性,它包含多个 animation-* 属性:

    1. animation-name :由 @keyframes 创建的动画名称,支持单个、多个
    2. animation-duration :动画周期时长,即完成一个动画周期所需的时间,时间单位
    3. animation-timing-function : 时间函数,即动画在每个周期的持续时间内如何进行,例如匀速、先快后慢、两头慢中间快或自定义运动时间曲线等等(文末附详细列表)
    4. animation-delay :动画延时时间,本质指动画执行之前等待的时间量,支持正(延后)负(提前)数,时间单位
    5. animation-iteration-count :动画运行次数,小于等于0表示不运行,infinite 表示永久运行
    6. animation-direction :运动方向,即播放动画的方向与 @keyframes 时间节点指向的关系,值有 normal(默认,正向)、reverse(反向)、alternate(往复)、alternate-reverse(反向往复)
    7. animation-fill-mode :动画结束时的状态,确切以言之,该属性设置 CSS 动画在执行之前和之后如何将样式应用于其目标。默认值是 none,可选值 forwards(保留最后帧状态)、backwards(首帧状态)
    8. animation-play-state :动画播放状态,设置动画播放(running)或暂停(paused

    属性较多,可以根据需要取舍,逐个设置时顺序不论:

    .ball {
        /* ... 这里是其它代码 */
        animation-name: move;
        animation-duration: 6s;
        animation-timing-function: linear;
        animation-iteration-count: 1;
        animation-fill-mode: forwards;
    }

    建议尽可能使用 animation 简写属性设置动画。

    三、动画实例

    (一)元素平移

    <style>
        .rect {
            width: 40px;
            height: 40px;
            background: cyan;
            transform: translate(0,100px);
            /* 匀速、8秒一个周期、永动、往复(来、回各算一个周期) */
            animation: move linear 8s infinite alternate;
        }
    
        /* 动画 :水平移动 */
        @keyframes move {
            to { transform: translate(800px,100px); }
        }
    </style>
    
    <div class="rect"></div>

    (二)元素旋转

    <style>
        .rect {
            margin: 200px;
            width: 180px;
            height: 180px;
            background: lightgreen;
            /* 慢-快-慢、5秒一个周期、2秒后开始、转3圈 */
            animation: rot 5s ease-in-out 2s 3;
        }
    
        /* 动画 :旋转360度 */
        @keyframes rot {
            100% { transform: rotate(360deg); }
        }
    </style>
    
    <div class="rect"></div>

    (三)元素形状变化(分步)

    <style>
        .rect {
            margin: 100px;
            width: 300px;
            height: 300px;
            border: 4px dotted purple;
            /* 匀速、6秒一个周期、分四步(阶跃运动)、保留最后状态 */
            animation: rot 6s steps(4, end) forwards;
            /* animation: rot 6s steps(3, start) forwards; */
        }
        
        /* 动画 :从矩形变成圆形 */
        @keyframes rot {
            0% { border-radius: 0%; }
            100% { border-radius: 50%; }
        }
    </style>
    
    <div class="rect"></div>

    (四)多个元素转圈圈

    <style>
        /* 父元素 */
        .pa { margin: 100px auto; width: 300px; height: 300px; border-radius: 50%; border: 3px dashed gray; position: relative; }
    
        /* 子元素 */
        .rect {
            position: absolute;
            width: 60px;
            height: 60px;
            background: tan;
            transform-origin: 150px 150px; /* 运动中心点坐标设在父元素中心点 */
            /* 6秒一个周期、匀速、运行一百次 */
            animation: ring 6s linear 100;
        }
        
        /* 第2、3子元素提前运行动画 */
        .rect:nth-of-type(2) { animation-delay: -2s; }
        .rect:nth-of-type(3) { animation-delay: -4s; }
    
        /* 动画 :旋转一周 */
        @keyframes ring {
            to { transform: rotate(1turn); }
        }
    </style>
    <div class="pa">
        <div class="rect"></div>
        <div class="rect"></div>
        <div class="rect"></div>
    </div>

    (五)元素做椭圆运动

    <style>
        /* 本例 offset-path 支持百分比,所以是自适应窗口尺寸的 */
        .ball {
            width: 80px;
            height: 80px;
            border-radius: 50%;
            background: linear-gradient(20deg, cyan, green);
            /* 椭圆路径 :以容器(这里是body)宽高各45%做长短轴半径、圆心在body中心点 */
            offset-path: ellipse(45% 45% at 50% 50%);
            animation: move linear 20s infinite;
        }
        /* 动画 :在路径中偏移 */
        @keyframes move {
            0% { offset-distance: 0%; }
            100% { offset-distance: 100%; }
        }
    </style>
    
    <div class="ball"></div>

    四、使用JS简单控制关键帧动画

    对关键帧动画最常见的需求是动画的播放与暂停操作。这可以使用JS直接操作元素的 animation-play-state 属性:前面已经提到过,属性值 running 表示播放、paused 表示暂停。看实例:

    🔹JS简单控制CSS关键帧动画

    <style>
        .kite {
            cursor: pointer;
            transform-origin: 100% 0;
            animation: skew ease-out 0.85s infinite alternate;
        }
        /* 动画 :在路径中偏移 */
        @keyframes skew {
            to { transform: skew(5deg); }
        }
    </style>
    
    <img class="kite" src="https://638183.freep.cn/638183/small/kite.png" alt="" title="点击播放/暂停" />
    
    <script>
        const kite = document.querySelector('.kite');
        kite.onclick = () => {
            // 使用 getAnimations API 获取元素的CSS动画相关信息
            const { playState } = kite.getAnimations()[0];
            // 如果动画运行中则暂停
            if (playState === 'running') {
                kite.style.setProperty('animation-play-state', 'paused');
            // 反之继续播放
            } else {
                kite.style.setProperty('animation-play-state', 'running');
            }
        };
    </script>

    Element.getAnimations() API 不是必须的,上例用到它主要是为了判断元素运行动画的状态(running或paused),从而决定点击图片时动画应暂停还是继续。在实际应用场景中,可以根据诸多情况来决定动画处于何种状态,例如音画帖中关键帧动画与音频的播放、暂停状态的紧密关联。另外,如果由于某种原因不方便直接操作CSS动画播放状态属性,我们可以使用 CSS 变量来代替 animation-play-state 的属性值,直接操作该变量,这样就不用针对每一个元素进行操作,而是批量操作所有使用了该 CSS 变量的所有元素:

    /* CSS 代码 :父元素定义 --state 变量值 */
    .pa {
        --state: running;
    }
    /* 子元素动画简写属性使用 --state 变量给 animation-play-state 属性赋值 */
    .son {
        animation: skew ease-out 0.85s infinite alternate var(--state);
    }
    
    // JS代码 :批量操作 .pa 下的所有使用了 var(--state) 的动画
    const pa = document.querySelector('.pa');
    // 如果要播放动画:
    pa.style.setProperty('--state', 'running');
    // 如果要暂停动画:
    pa.style.setProperty('--state', 'paused');

    对于非无穷大的动画播放次数,有时候可能需要监听动画的开始、结束动作,以便决定动画流程的下一步环节,这时有两个JS事件可用:animationstart(动画开始)和 animationend(动画结束):

    🔹JS监听动画开始和动画结束事件

    <style>
        .rect { left: 20px; top: 100px; width: 200px; height: 100px; display: grid; place-items: center; background: wheat; position: absolute; }
        .ani1 { animation: move linear 16s forwards; }
        .ani2 { animation: move linear 8s reverse forwards; }
        @keyframes move {
            to { left: calc(100% - 220px); }
        }
    </style>
    
    <div class="rect">点击开始动画</div>
    
    <script>
        const rect = document.querySelector('.rect');
        const anis = ['ani1', 'ani2']; // 动画数组
        let idx = 0; // 动画运行计数
        
        // 动画开始事件
        rect.onanimationstart = () => rect.textContent = `动画 :${anis[idx % 2]}`;
        
        // 动画结束事件
        rect.onanimationend = () => {
            rect.classList.remove(anis[idx % 2]);
            idx += 1;
            setTimeout( () => rect.classList.add(anis[idx % 2]), 0);
        };
        
        rect.onclick = () => {
            // 若动画尚未开始
            if (!rect.getAnimations()[0]) {
                rect.classList.add(anis[idx]); // 开始动画
            // 若动画已经开始
            } else {
                const { playState } = rect.getAnimations()[0]; // 获取动画状态
                // 暂停或继续动画
                rect.style.setProperty(
                    'animation-play-state',
                    playState === 'running' ? 'paused' : 'running'
                );
            }
            
        };
    </script>

    JS 操作 CSS 关键帧动画远不止这些,限于篇幅,本文点到而止。

    附:animation-timing-function 属性值及其含义

    属性值 属性值说明
    linear 匀速,对应于贝赛尔曲线 cubic-bezier(0, 0, 1, 1)【第一控制点 {0,0},第二控制点{1,1}】
    ease 慢-快-慢(缺省默认,与 ease-in-out相似,但在开始时加速更陡,对应于 cubic-bezier(0.25, 0.1, 0.25, 1.0)
    ease-in 先慢后快,对应于 cubic-bezier(0.42, 0.0, 1.0, 1.0)
    ease-out 先快后慢,对应于 cubic-bezier(0.0, 0.0, 0.58, 1.0)
    ease-in-out 慢-快-慢,开始时表现同 ease-in,结束时表现同 ease-out,对应于 cubic-bezier(0.42, 0.0, 0.58, 1.0)
    cubic-bezier(x1, y1, x2, y2) 三次贝塞尔曲线,速度曲线,n1~y2可能的值都是从 0 到 1 的数值
    step-start 在变化过程中,都是以下一帧的显示效果来填充间隔动画
    step-end 在变化过程中,都是以上一帧的显示效果来填充间隔动画
    steps() 阶跃函数,用于实现逐帧动画(如精灵图切换),动画过程是断断续续的。可以传入两个参数,第一个是一个大于0的整数,他是将间隔动画等分成指定数目的小间隔动画,然后根据第二个参数来决定显示效果。第二个参数设置后其实和step-start,step-end同义,在分成的小间隔动画中判断显示效果
  • TA的每日心情
    开心
    2026-7-27 10:27
  • 签到天数: 792 天

    [LV.10]以坛为家III

    559

    主题

    3万

    回帖

    9万

    积分

    贵宾

    Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7Rank: 7

    花潮美女鼠牛虎兔龙蛇马羊猴鸡狗猪缤纷心情心曲飞扬花好月圆飞龙在天音画大师天籁妙音共看流星风雨同行我心永远喜乐安康花潮贵宾

    发表于 2026-7-27 15:08 | 显示全部楼层
    仔细看了,黑黑老师讲解详细,收藏学习。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2026-7-27 10:54
  • 签到天数: 1882 天

    [LV.Master]伴坛终老

    3289

    主题

    13万

    回帖

    29万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9Rank: 9

    花潮帅哥鼠牛虎兔龙蛇马羊猴鸡狗猪多彩人生星月交辉奔放热烈海样胸怀春风拂面火热情怀优雅迷人神秘浪漫相遇之美鹰傲苍穹花好月圆紫色情节飞龙在天王者至尊大将风范音画大师天籁妙音共看流星风雨同行我心永远幸福快乐喜乐安康侠骨柔肠心想事成开朗大方花潮管理

     楼主| 发表于 2026-7-27 18:42 | 显示全部楼层
    梦江南 发表于 2026-7-27 15:08
    仔细看了,黑黑老师讲解详细,收藏学习。

    音画帖基本少不了 CSS 动画,这个讲的是 animation 动画
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    小黑屋|手机版|Archiver|服务支持:DZ动力|huachaowang.com Inc. ( 蜀ICP备17032287号-1 )

    GMT+8, 2026-7-27 19:23 , Processed in 0.070317 second(s), 24 queries .

    Powered by Discuz! X3.4

    © 2001-2013 Comsenz Inc.

    快速回复 返回顶部 返回列表