1. 基础概念:了解 HTML、CSS、JS 在动画中各自扮演的角色。
  2. 核心技术:详细介绍实现动画的几种主要方法。
  3. 完整实例:动手创建一个带有多种动画效果的网页。

基础概念:三者的分工

想象一下制作一部动画电影:

js css html写动画网页
(图片来源网络,侵删)
  • HTML (骨架):负责定义网页的结构和内容,它就像电影的场景和角色,告诉浏览器哪里有元素、这个元素是什么(比如一个方块、一张图片、一段文字),动画的“演员”就是由 HTML 定义的。
  • CSS (外观与动作):负责元素的样式和一部分动画效果,它就像角色的服装、化妆和动作设计,你可以用 CSS 来改变元素的颜色、大小、位置,并让这些变化平滑过渡,从而产生动画。
  • JavaScript (导演与大脑):负责控制动画的时机、逻辑和交互,它就像导演,决定什么时候开始动画、什么时候结束、如何根据用户的操作(如点击、鼠标移动)来改变剧情,JS 可以动态地修改 CSS 属性,或者操作 HTML 元素,实现更复杂、更智能的动画。

核心技术:实现动画的几种方法

CSS 过渡

这是最简单、最常用的方法,当元素的 CSS 属性值发生变化时,过渡可以让这个变化过程持续一段时间,而不是瞬间完成。

适用场景:简单的状态变化,如悬停效果、点击后的样式切换。

示例代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">CSS 过渡示例</title>
    <style>
        /* 1. 定义初始状态的样式 */
        .box {
            width: 100px;
            height: 100px;
            background-color: steelblue;
            /* 关键:指定哪些属性需要过渡,以及过渡的持续时间 */
            transition: width 0.5s ease, background-color 0.5s ease;
        }
        /* 2. 定义最终状态的样式(通常通过伪类或JS添加) */
        .box:hover {
            width: 200px;
            background-color: orange;
        }
    </style>
</head>
<body>
    <h2>将鼠标悬停在方块上</h2>
    <div class="box"></div>
</body>
</html>

解释

js css html写动画网页
(图片来源网络,侵删)
  • .box 是我们的演员。
  • transition 属性告诉浏览器:widthbackground-color 这两个属性发生变化,请用 0.5 秒的时间,并以 ease(先快后慢)的节奏来完成这个变化。
  • hover 是一个 CSS 伪类,当鼠标移动到 .box 上时,触发其内部的样式变化,从而触发了过渡动画。

CSS 关键帧动画

当你需要创建一个更复杂、多步骤的动画序列时,关键帧动画是最佳选择,它定义了动画在不同时间点的状态(关键帧),浏览器会自动计算中间状态。

适用场景:循环动画、复杂的路径动画、加载动画。

示例代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">CSS 关键帧动画示例</title>
    <style>
        .loader {
            width: 50px;
            height: 50px;
            border: 5px solid #f3f3f3; /* 灰色背景 */
            border-top: 5px solid #3498db; /* 蓝色顶部 */
            border-radius: 50%;
            /* 关键:使用 animation 属性 */
            animation: spin 1s linear infinite;
        }
        /* 定义关键帧动画 */
        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }
    </style>
</head>
<body>
    <h2>一个旋转的加载器</h2>
    <div class="loader"></div>
</body>
</html>

解释

js css html写动画网页
(图片来源网络,侵删)
  • @keyframes spin 定义了一个名为 spin 的动画,它包含两个关键帧:0%(动画开始时)元素不旋转,100%(动画结束时)元素旋转 360 度。
  • .loader 上的 animation 属性将这个动画应用到了元素上:
    • spin: 使用哪个 @keyframes
    • 1s: 动画持续 1 秒。
    • linear: 动画速度是匀速的。
    • infinite: 动画无限次循环。

JavaScript 动画 (JS + requestAnimationFrame)

这是最强大、最灵活的方法,性能也最好,通过 JavaScript 动态地修改元素的样式,通常与 requestAnimationFrame API 配合使用。

requestAnimationFrame 是浏览器专门为动画提供的 API,它会告诉浏览器:“请在下一次重绘之前调用这个函数来更新动画。” 这样可以确保动画与浏览器的刷新率同步,非常流畅且节能。

适用场景:游戏、复杂的交互动画、数据可视化、需要精确控制动画过程的场景。

示例代码:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">JS 动画示例</title>
    <style>
        .js-box {
            width: 100px;
            height: 100px;
            background-color: purple;
            position: absolute; /* 必须是定位元素才能移动 */
            top: 50px;
            left: 50px;
        }
        button {
            margin-top: 150px;
            padding: 10px 15px;
            font-size: 16px;
        }
    </style>
</head>
<body>
    <h2>点击按钮让方块移动</h2>
    <div class="js-box" id="movingBox"></div>
    <button id="moveButton">移动方块</button>
    <script>
        const box = document.getElementById('movingBox');
        const button = document.getElementById('moveButton');
        let position = 50; // 初始位置
        let isMoving = false;
        button.addEventListener('click', () => {
            if (isMoving) return; // 防止重复点击
            isMoving = true;
            moveBox();
        });
        function moveBox() {
            // 每次调用,位置增加 5 像素
            position += 5; 
            // 更新方块的 left 属性
            box.style.left = position + 'px';
            // 如果还没有到达 500px,就继续请求下一帧
            if (position < 500) {
                requestAnimationFrame(moveBox);
            } else {
                isMoving = false; // 动画结束
            }
        }
    </script>
</body>
</html>

解释

  1. 获取元素:JS 通过 document.getElementById 获取了方块和按钮。
  2. 事件监听:给按钮添加了 click 事件,当点击时,执行 moveBox 函数。
  3. 动画循环
    • moveBox 函数每次执行时,都会更新 position 变量。
    • 然后通过 box.style.left 将新的位置应用到元素上,浏览器会自动重绘。
    • if (position < 500) 判断动画是否结束。
    • 如果没有结束,就调用 requestAnimationFrame(moveBox),告诉浏览器在下一帧继续执行 moveBox
    • 这个循环过程非常快,看起来就是流畅的动画。

完整实例:一个酷炫的动画网页

我们把以上技术结合起来,创建一个包含多种动画效果的网页。

最终效果

  1. 页面加载时,标题从上方淡入并滑入。
  2. 卡片在鼠标悬停时,会放大并显示一个“查看详情”的按钮。
  3. 点击“开始动画”按钮,一个圆形元素会沿着一条路径移动。

代码 (index.html)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">动画网页示例</title>
    <style>
        /* --- 全局和基础样式 --- */
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            background-color: #f0f2f5;
            color: #333;
            margin: 0;
            padding: 20px;
        }
        /* --- 标题动画 (CSS 关键帧) --- */
        .main-title {
            text-align: center;
            font-size: 3em;
            color: #2c3e50;
            /* 初始状态:透明,向上移动 */
            opacity: 0;
            transform: translateY(-50px);
            /* 应用动画:持续1秒,缓动函数,延迟0.5秒后播放,只播放一次 */
            animation: fadeInSlide 1s ease-out 0.5s forwards;
        }
        @keyframes fadeInSlide {
            to { /* 最终状态 */
                opacity: 1;
                transform: translateY(0);
            }
        }
        /* --- 卡片容器 --- */
        .card-container {
            display: flex;
            justify-content: center;
            gap: 30px;
            margin: 50px 0;
            flex-wrap: wrap;
        }
        /* --- 卡片动画 (CSS 过渡) --- */
        .card {
            width: 250px;
            height: 350px;
            background: white;
            border-radius: 10px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            overflow: hidden;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            cursor: pointer;
        }
        .card:hover {
            transform: translateY(-10px) scale(1.02); /* 悬停时上移并放大 */
            box-shadow: 0 8px 16px rgba(0,0,0,0.2);
        }
        .card img {
            width: 100%;
            height: 70%;
            object-fit: cover;
        }
        .card-content {
            padding: 15px;
            text-align: center;
        }
        .card-button {
            background-color: #3498db;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 5px;
            margin-top: 10px;
            opacity: 0; /* 初始隐藏 */
            transition: opacity 0.3s ease;
        }
        .card:hover .card-button {
            opacity: 1; /* 悬停时显示 */
        }
        /* --- 路径动画区域 --- */
        .animation-area {
            position: relative;
            height: 200px;
            background-color: #ecf0f1;
            border-radius: 10px;
            margin: 40px auto;
            max-width: 600px;
            overflow: hidden;
        }
        .moving-ball {
            width: 40px;
            height: 40px;
            background-color: #e74c3c;
            border-radius: 50%;
            position: absolute;
            top: 50%;
            left: 20px;
            transform: translateY(-50%);
        }
        .control-button {
            display: block;
            margin: 20px auto;
            padding: 12px 25px;
            font-size: 18px;
            background-color: #27ae60;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
        }
        .control-button:hover {
            background-color: #229954;
        }
    </style>
</head>
<body>
    <h1 class="main-title">欢迎来到动画世界</h1>
    <div class="card-container">
        <div class="card">
            <img src="https://via.placeholder.com/250x175/3498db/ffffff?text=图片1" alt="卡片图片">
            <div class="card-content">
                <h3>卡片一</h3>
                <p>这是一个使用 CSS 过渡制作的悬停效果卡片。</p>
                <button class="card-button">查看详情</button>
            </div>
        </div>
        <div class="card">
            <img src="https://via.placeholder.com/250x175/9b59b6/ffffff?text=图片2" alt="卡片图片">
            <div class="card-content">
                <h3>卡片二</h3>
                <p>鼠标悬停试试看,会有惊喜哦!</p>
                <button class="card-button">查看详情</button>
            </div>
        </div>
        <div class="card">
            <img src="https://via.placeholder.com/250x75/e67e22/ffffff?text=图片3" alt="卡片图片">
            <div class="card-content">
                <h3>卡片三</h3>
                <p>组合使用 CSS 可以创造出丰富的交互。</p>
                <button class="card-button">查看详情</button>
            </div>
        </div>
    </div>
    <button class="control-button" id="startPathAnimation">开始路径动画</button>
    <div class="animation-area" id="animationArea">
        <div class="moving-ball" id="movingBall"></div>
    </div>
    <script>
        // --- 路径动画 (JS + requestAnimationFrame) ---
        const startButton = document.getElementById('startPathAnimation');
        const ball = document.getElementById('movingBall');
        const animationArea = document.getElementById('animationArea');
        let isAnimating = false;
        startButton.addEventListener('click', () => {
            if (isAnimating) return;
            isAnimating = true;
            startButton.textContent = '动画中...';
            startButton.disabled = true;
            // 获取动画区域的宽度和球的宽度,以计算终点
            const areaWidth = animationArea.offsetWidth;
            const ballWidth = ball.offsetWidth;
            const endPosition = areaWidth - ballWidth - 20; // 减去左边距和球的宽度
            // 重置球的位置
            ball.style.left = '20px';
            let position = 20; // 起始位置
            const speed = 5; // 每次移动的像素
            function animate() {
                position += speed;
                ball.style.left = position + 'px';
                // 如果球还没有到达终点,继续动画
                if (position < endPosition) {
                    requestAnimationFrame(animate);
                } else {
                    // 动画结束
                    isAnimating = false;
                    startButton.textContent = '重新开始';
                    startButton.disabled = false;
                }
            }
            // 启动动画
            requestAnimationFrame(animate);
        });
    </script>
</body>
</html>

总结与建议

动画类型 优点 缺点 适用场景
CSS 过渡 代码简单,性能好,由浏览器优化。 只能定义开始和结束状态。 简单的交互反馈,如悬停、点击、焦点状态。
CSS 关键帧 可以定义复杂的动画序列,无需 JS。 动画路径固定,难以实现交互逻辑。 循环动画、加载动画、装饰性动画。
JS 动画 最灵活,可处理复杂逻辑、物理模拟、与用户深度交互。 代码复杂,需要手动优化性能。 游戏、数据可视化、复杂的页面交互动画。

给你的建议

  • 从 CSS 开始:对于 80% 的网页动画需求,CSS 过渡和关键帧已经足够,它们简单、高效,是你的首选。
  • 按需引入 JS:当 CSS 无法满足你的需求时(动画的路径需要根据用户输入实时计算,或者需要暂停、倒放等复杂控制),再使用 JavaScript 动画。
  • 性能优先:尽量使用 transform (如 translateX, scale, rotate) 和 opacity 属性来做动画,因为这些属性不会引起页面的重排,性能最好,避免频繁修改 width, height, margin, top, left 等属性。