核心思路

无论使用哪种方法,实现飘动图片的核心思路都是一样的:

飘动图片 网页javascript
(图片来源网络,侵删)
  1. 定位: 将图片设置为绝对定位,这样它就可以脱离正常的文档流,我们可以用 topleft 属性自由控制它的位置。
  2. 动画: 使用 JavaScript 定期(每 16 毫秒,约等于 60 帧/秒)更新图片的 topleft 值。
  3. 路径: 更新值的规律决定了飘动的路径,最常见的路径是:
    • 正弦波: 模拟自然飘落的轨迹,左右晃动,同时缓慢下落。
    • 圆形: 图片沿着一个圆形路径运动。
    • 随机: 图片随机改变位置,产生“漂浮不定”的感觉。

下面我们来看具体的实现方法。


使用 requestAnimationFrame (推荐)

这是现代浏览器中最推荐的方法,专门用于制作高性能的动画,它比 setInterval 更高效,因为它会浏览器的重绘周期同步,避免不必要的渲染。

示例:模拟雪花飘落(正弦波路径)

这个效果会让图片从屏幕上方随机位置出现,然后像雪花一样左右飘动并缓慢下落。

HTML 代码 (index.html)

飘动图片 网页javascript
(图片来源网络,侵删)
<!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 {
            margin: 0;
            height: 100vh;
            background-color: #222;
            overflow: hidden; /* 防止出现滚动条 */
            font-family: sans-serif;
        }
        /* 这是飘动图片的容器 */
        .floating-container {
            position: relative;
            width: 100%;
            height: 100%;
        }
        /* 飘动图片的样式 */
        .floating-image {
            position: absolute;
            width: 50px; /* 设置图片大小 */
            height: 50px;
            /* 使用一个雪花图标作为示例 */
            background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M12 2l-1.09 3.26L7 7l3.26 1.09L12 12l1.74-3.91L17 7l-3.91-1.74L12 2zm0 8l-1.09 3.26L7 15l3.26 1.09L12 20l1.74-3.91L17 15l-3.91-1.74L12 10z"/></svg>');
            background-size: contain;
            background-repeat: no-repeat;
            opacity: 0.8;
        }
    </style>
</head>
<body>
    <div class="floating-container" id="container">
        <!-- 图片将通过 JavaScript 动态添加 -->
    </div>
    <script src="script.js"></script>
</body>
</html>

JavaScript 代码 (script.js)

document.addEventListener('DOMContentLoaded', () => {
    const container = document.getElementById('container');
    // 1. 创建飘动图片的类
    class FloatingImage {
        constructor(imgSrc, size = 50) {
            // 创建图片元素
            this.element = document.createElement('img');
            this.element.src = imgSrc;
            this.element.className = 'floating-image';
            this.element.style.width = `${size}px`;
            this.element.style.height = `${size}px`;
            // 初始化位置和运动参数
            this.x = Math.random() * window.innerWidth; // 随机水平起始位置
            this.y = -50; // 从屏幕上方开始
            this.speed = 1 + Math.random() * 2; // 下落速度 (1-3)
            this.amplitude = 20 + Math.random() * 30; // 左右摆动的幅度 (20-50)
            this.frequency = 0.01 + Math.random() * 0.02; // 摆动频率 (控制快慢)
            this.offset = Math.random() * Math.PI * 2; // 随机初始相位,让所有雪花不同步
            // 将图片添加到容器中
            container.appendChild(this.element);
        }
        // 2. 更新图片位置的方法
        update() {
            // 使用正弦函数计算水平偏移,产生左右飘动效果
            this.x += Math.sin(this.y * this.frequency + this.offset) * this.amplitude * 0.05;
            // 垂直下落
            this.y += this.speed;
            // 3. 将计算出的位置应用到图片元素上
            this.element.style.transform = `translate(${this.x}px, ${this.y}px)`;
            // 4. 检查是否飘出屏幕,如果是则重置位置
            if (this.y > window.innerHeight) {
                this.y = -50;
                this.x = Math.random() * window.innerWidth;
            }
        }
    }
    // 5. 创建多个飘动图片实例
    const images = [];
    const imageCount = 15; // 控制飘动图片的数量
    for (let i = 0; i < imageCount; i++) {
        // 你可以换成你自己的图片路径,'path/to/your/image.png'
        images.push(new FloatingImage('path/to/your/image.png'));
    }
    // 6. 动画循环
    function animate() {
        // 遍历所有图片并更新它们的位置
        images.forEach(image => image.update());
        // 请求下一帧动画
        requestAnimationFrame(animate);
    }
    // 启动动画
    animate();
});

代码解析:

  1. FloatingImage: 我们用类来封装每个飘动图片的状态(位置、速度等)和行为(更新位置),这样代码结构更清晰。
  2. update() 方法: 这是动画的核心,它根据预设的数学公式(这里是正弦波)计算新的 xy 坐标。
    • Math.sin(): 产生一个 -1 到 1 之间的值,我们用它来控制水平方向的左右偏移。
    • this.y * this.frequency: 让摆动随着下落而变化,看起来更自然。
    • this.offset: 每个图片的初始相位不同,确保它们不会同时摆向一边。
  3. transform: 我们使用 transform: translate(x, y) 来移动图片,而不是直接修改 toplefttransform 性能更好,因为它可以利用 GPU 加速。
  4. requestAnimationFrame(animate): 这是动画循环的“心脏”。animate 函数在每一帧都会被调用,更新所有图片的位置,然后请求浏览器在下一帧再次调用它,形成流畅的动画。

使用 CSS @keyframes 和 JavaScript 控制位置

这种方法结合了 CSS 动画的流畅性和 JavaScript 的灵活性,我们用 CSS 控制图片自身的旋转和缩放等动画,用 JavaScript 控制它在页面上的移动轨迹。

HTML 代码 (index.html)

飘动图片 网页javascript
(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">CSS + JS 飘动图片</title>
    <style>
        body {
            margin: 0;
            height: 100vh;
            background: linear-gradient(to bottom, #87CEEB, #E0F6FF);
            overflow: hidden;
        }
        .floating-item {
            position: absolute;
            width: 60px;
            height: 60px;
            /* 图片本身的动画:旋转和轻微缩放 */
            animation: floatAnimation 3s infinite ease-in-out;
        }
        @keyframes floatAnimation {
            0%, 100% { transform: rotate(0deg) scale(1); }
            50% { transform: rotate(10deg) scale(1.1); }
        }
    </style>
</head>
<body>
    <div id="css-float-container"></div>
    <script src="css-js-script.js"></script>
</body>
</html>

JavaScript 代码 (css-js-script.js)

document.addEventListener('DOMContentLoaded', () => {
    const container = document.getElementById('css-float-container');
    const items = [];
    // 创建一个函数来更新所有元素的位置
    function updatePositions() {
        items.forEach(item => {
            // 获取当前位置
            let currentX = parseFloat(item.element.style.left) || 0;
            let currentY = parseFloat(item.element.style.top) || 0;
            // 更新位置(向右下角移动)
            currentX += 1;
            currentY += 0.5;
            // 如果移出屏幕,重置到左上角
            if (currentX > window.innerWidth || currentY > window.innerHeight) {
                currentX = -60;
                currentY = Math.random() * window.innerHeight;
            }
            // 应用新位置
            item.element.style.left = `${currentX}px`;
            item.element.style.top = `${currentY}px`;
        });
        // 使用 setTimeout 控制更新频率
        setTimeout(updatePositions, 16); // 大约 60fps
    }
    // 创建多个飘动元素
    for (let i = 0; i < 8; i++) {
        const img = document.createElement('img');
        img.src = 'path/to/your/image.png'; // 替换为你的图片
        img.className = 'floating-item';
        // 随机初始位置
        img.style.left = `${Math.random() * window.innerWidth}px`;
        img.style.top = `${Math.random() * window.innerHeight}px`;
        container.appendChild(img);
        // 存储元素引用
        items.push({ element: img });
    }
    // 启动位置更新循环
    updatePositions();
});

这种方法的特点:

  • 优点: CSS 动画 (floatAnimation) 非常流畅,因为它也由浏览器优化,你可以专注于用 JS 控制宏观的移动路径。
  • 缺点: 位置更新的精确控制和性能不如 requestAnimationFramesetTimeout 的间隔时间只是近似值,可能不够精确。

使用第三方库 (GSAP)

如果你需要更复杂、更强大的动画效果,或者希望用更简洁的代码实现,可以考虑使用专业的动画库,如 GSAP (GreenSock Animation Platform)

第一步:引入 GSAP 库 在 HTML 的 <head> 中添加 GSAP 的 CDN 链接。

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>

第二步:编写 JavaScript

document.addEventListener('DOMContentLoaded', () => {
    const container = document.getElementById('container');
    // 创建图片元素
    const myImage = document.createElement('img');
    myImage.src = 'path/to/your/image.png';
    myImage.style.position = 'absolute';
    myImage.style.width = '80px';
    container.appendChild(myImage);
    // 使用 GSAP 创建动画
    // .to() 方法用于创建一个从当前状态到目标状态的动画
    gsap.to(myImage, {
        // 目标属性
        x: "+=100", // 水平移动 100px (相对于当前位置)
        y: "+=100", // 垂直移动 100px
        rotation: 360, // 旋转 360 度
        duration: 2, // 动画持续 2 秒
        repeat: -1, // 无限重复
        yoyo: true, // 来回播放
        ease: "power1.inOut" // 缓动效果,让动画更自然
    });
    // 创建一个沿圆形路径移动的动画
    const anotherImage = document.createElement('img');
    anotherImage.src = 'path/to/your/other-image.png';
    anotherImage.style.position = 'absolute';
    anotherImage.style.width = '60px';
    container.appendChild(anotherImage);
    gsap.to(anotherImage, {
        motionPath: {
            path: "M100,100 Q250,50 400,100 T700,100", // 定义一个贝塞尔曲线路径
            autoRotate: true // 让图片沿路径方向旋转
        },
        duration: 4,
        repeat: -1
    });
});

GSAP 的优势:

  • 性能卓越: GSAP 是业界性能最好的动画库之一。
  • 功能强大: 可以轻松实现各种复杂动画,如路径动画、时间轴控制、滚动触发等。
  • 代码简洁: 只需几行代码就能实现复杂的动画效果,大大提高了开发效率。

总结与选择

方法 优点 缺点 适用场景
requestAnimationFrame 性能最好,完全控制,无需额外库 需要自己写动画逻辑,代码量稍多 对性能要求高的自定义动画,如游戏、粒子效果、复杂飘落。
CSS + JS CSS 动画流畅,JS 控制灵活 位置控制性能稍逊,逻辑耦合 需要图片自身有动画(如旋转),同时又在页面上移动的场景。
GSAP 功能最强代码最简洁,性能极佳 需要引入外部库 快速开发复杂动画,商业项目,或对动画效果有高要求的场景。

对于初学者或大多数“飘动图片”的需求,方法一 (requestAnimationFrame) 是最佳选择,因为它既保证了性能,又能让你深入理解动画的原理,如果你追求开发效率和更酷炫的效果,直接上手 GSAP 会事半功倍。