在前端开发里,动画效果能让网页变得更生动有趣。实现动画的方法有不少,今天就来聊聊 JavaScript 里的 requestAnimationFrame 和 CSS 动画,看看它们各自的特点,并且对比一下。

一、requestAnimationFrame 基础介绍

1. 什么是 requestAnimationFrame

requestAnimationFrame 是 JavaScript 提供的一个函数,它可以让我们在浏览器下次重绘之前执行一个回调函数。简单来说,就是能帮我们控制动画的每一帧,让动画更流畅。

2. 示例代码

// JavaScript 技术栈
// 定义一个元素
const box = document.createElement('div');
box.style.width = '50px';
box.style.height = '50px';
box.style.backgroundColor = 'blue';
document.body.appendChild(box);

// 定义动画函数
function animate() {
    // 获取当前元素的 left 值
    let left = parseInt(box.style.left) || 0;
    // 每次移动 1 像素
    left += 1;
    box.style.left = left + 'px';

    // 如果移动到 200 像素就停止
    if (left < 200) {
        // 请求下一帧动画
        requestAnimationFrame(animate);
    }
}

// 开始动画
animate();

这个例子里,我们创建了一个蓝色的方块,然后用 requestAnimationFrame 让它向右移动,直到移动到 200 像素的位置。

二、CSS 动画基础介绍

1. 什么是 CSS 动画

CSS 动画是通过 CSS 来控制元素的动画效果,主要用到 @keyframes 规则。我们可以定义动画的关键帧,然后把动画应用到元素上。

2. 示例代码

/* CSS 技术栈 */
/* 定义动画 */
@keyframes move {
    from {
        left: 0;
    }
    to {
        left: 200px;
    }
}

/* 应用动画到元素 */
.box {
    width: 50px;
    height: 50px;
    background-color: red;
    position: relative;
    /* 应用动画 */
    animation: move 2s linear;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="styles.css">
    <title>CSS 动画示例</title>
</head>
<body>
    <div class="box"></div>
</body>
</html>

这里我们定义了一个名为 move 的动画,让元素从左边 0 像素移动到 200 像素,然后把这个动画应用到一个红色的方块上。

三、应用场景

1. requestAnimationFrame 的应用场景

  • 复杂交互动画:当动画需要根据用户的交互来动态调整时,requestAnimationFrame 就很有用。比如,用户拖动一个元素,元素的移动需要实时响应,这时就可以用 requestAnimationFrame 来控制。
// JavaScript 技术栈
const dragBox = document.createElement('div');
dragBox.style.width = '50px';
dragBox.style.height = '50px';
dragBox.style.backgroundColor = 'green';
document.body.appendChild(dragBox);

let isDragging = false;
let startX, startY;

dragBox.addEventListener('mousedown', function (e) {
    isDragging = true;
    startX = e.clientX - parseInt(dragBox.style.left) || 0;
    startY = e.clientY - parseInt(dragBox.style.top) || 0;
});

document.addEventListener('mousemove', function (e) {
    if (isDragging) {
        function updatePosition() {
            dragBox.style.left = (e.clientX - startX) + 'px';
            dragBox.style.top = (e.clientY - startY) + 'px';
            requestAnimationFrame(updatePosition);
        }
        requestAnimationFrame(updatePosition);
    }
});

document.addEventListener('mouseup', function () {
    isDragging = false;
});

这个例子里,用户可以拖动绿色的方块,通过 requestAnimationFrame 实时更新方块的位置。

  • 游戏开发:在游戏里,动画需要根据游戏的逻辑来动态变化,比如角色的移动、攻击等。requestAnimationFrame 可以很好地满足这种需求。

2. CSS 动画的应用场景

  • 简单过渡效果:像按钮的悬停效果、菜单的展开收起等简单的过渡动画,用 CSS 动画就很合适。
/* CSS 技术栈 */
.button {
    padding: 10px 20px;
    background-color: #007BFF;
    color: white;
    border: none;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

.button:hover {
    background-color: #0056b3;
}

这个例子里,当鼠标悬停在按钮上时,按钮的背景颜色会有一个过渡效果。

  • 页面加载动画:在页面加载时显示一些动画,让用户等待时不会觉得枯燥。
/* CSS 技术栈 */
.loader {
    border: 16px solid #f3f3f3;
    border-top: 16px solid #3498db;
    border-radius: 50%;
    width: 120px;
    height: 120px;
    animation: spin 2s linear infinite;
    margin: 50px auto;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

这里定义了一个加载动画,一个旋转的圆圈。

四、技术优缺点

1. requestAnimationFrame 的优缺点

优点

  • 性能优化:requestAnimationFrame 会根据浏览器的刷新频率来执行回调函数,避免了不必要的重绘,提高了性能。
  • 动态控制:可以根据用户的交互或者游戏逻辑动态调整动画,灵活性很高。

缺点

  • 代码复杂度:相比 CSS 动画,requestAnimationFrame 的代码要复杂一些,需要自己处理动画的每一帧。
  • 兼容性问题:虽然现在大部分浏览器都支持 requestAnimationFrame,但在一些旧版本的浏览器里可能会有兼容性问题。

2. CSS 动画的优缺点

优点

  • 代码简洁:只需要在 CSS 里定义动画规则,然后应用到元素上就可以了,代码很简洁。
  • 性能较好:CSS 动画是由浏览器的渲染引擎直接处理的,性能比较好。

缺点

  • 缺乏动态控制:CSS 动画一旦定义好,就很难根据用户的交互或者其他条件动态调整。
  • 功能有限:对于一些复杂的动画效果,CSS 动画可能无法实现。

五、注意事项

1. requestAnimationFrame 注意事项

  • 取消动画:如果动画不需要继续执行,要记得取消 requestAnimationFrame,避免不必要的性能消耗。
// JavaScript 技术栈
let animationId;

function startAnimation() {
    function animate() {
        // 动画逻辑
        animationId = requestAnimationFrame(animate);
    }
    animationId = requestAnimationFrame(animate);
}

function stopAnimation() {
    cancelAnimationFrame(animationId);
}
  • 性能优化:在动画函数里尽量减少 DOM 操作,因为 DOM 操作比较消耗性能。

2. CSS 动画注意事项

  • 动画结束状态:CSS 动画结束后,元素会回到初始状态或者保持最后一帧的状态,需要根据需求设置 animation-fill-mode 属性。
/* CSS 技术栈 */
.box {
    width: 50px;
    height: 50px;
    background-color: yellow;
    position: relative;
    animation: move 2s linear;
    /* 保持最后一帧的状态 */
    animation-fill-mode: forwards;
}

@keyframes move {
    from {
        left: 0;
    }
    to {
        left: 200px;
    }
}
  • 兼容性:不同浏览器对 CSS 动画的支持可能会有差异,需要进行适当的前缀处理。

六、文章总结

总的来说,requestAnimationFrame 和 CSS 动画各有优缺点。如果需要实现复杂的交互动画或者游戏动画,requestAnimationFrame 是更好的选择,它可以让我们灵活地控制动画的每一帧。而如果只是实现简单的过渡效果或者页面加载动画,CSS 动画就足够了,它代码简洁,性能也不错。在实际开发中,我们可以根据具体的需求来选择合适的动画实现方式。