使用 CSS @keyframes 动画(推荐,最常用)
这是最简单、性能最好且最常用的方法,它完全使用CSS实现,无需JavaScript,非常适合制作无缝循环的图片轮播。

(图片来源网络,侵删)
核心思路:
- 容器:创建一个固定宽度和高度的容器,并设置
overflow: hidden来隐藏超出部分的图片。 - 图片列表:将所有图片放在一个
<div>中,这个<div>的宽度是所有图片宽度之和。 - 动画:使用CSS
@keyframes创建一个从左到右的平移动画,动画结束时,图片列表的位置会回到起点,但由于我们复制了第一张图片,所以看起来是连续的。
实现步骤:
HTML 结构
我们需要一个容器 .scroll-container,里面包含一个图片列表 .scroll-content,为了实现无缝循环,图片列表的第一张图片需要被复制并添加到列表的末尾。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">CSS 连续滚动图片</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>横向连续滚动图片展示</h1>
<div class="scroll-container">
<!-- 图片列表 -->
<div class="scroll-content">
<!-- 原始图片 -->
<img src="https://picsum.photos/seed/img1/300/200.jpg" alt="图片 1">
<img src="https://picsum.photos/seed/img2/300/200.jpg" alt="图片 2">
<img src="https://picsum.photos/seed/img3/300/200.jpg" alt="图片 3">
<img src="https://picsum.photos/seed/img4/300/200.jpg" alt="图片 4">
<img src="https://picsum.photos/seed/img5/300/200.jpg" alt="图片 5">
<!-- 为了无缝循环,将第一张图片复制一份放在最后 -->
<img src="https://picsum.photos/seed/img1/300/200.jpg" alt="图片 1 (副本)">
</div>
</div>
</body>
</html>
CSS 样式
这是实现滚动的关键。

(图片来源网络,侵删)
/* style.css */
/* 基础样式 */
body {
font-family: sans-serif;
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
h1 {
color: #333;
}
/* 1. 滚动容器 */
.scroll-container {
width: 800px; /* 容器宽度 */
height: 220px; /* 容器高度,比图片高一点 */
overflow: hidden; /* 关键:隐藏超出容器的部分 */
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
position: relative; /* 为内部动画提供定位上下文 */
}
/* 2. 图片列表 */
.scroll-content {
display: flex; /* 使用 Flexbox 布局,让图片水平排列 */
width: calc(300px * 6); /* 关键:宽度为所有图片宽度之和 (5张原始 + 1张副本) */
animation: scroll 20s linear infinite; /* 关键:应用动画 */
}
/* 3. 单张图片样式 */
.scroll-content img {
width: 300px;
height: 200px;
object-fit: cover; /* 保证图片不变形 */
flex-shrink: 0; /* 防止图片被压缩 */
}
/* 4. 核心动画定义 */
@keyframes scroll {
0% {
transform: translateX(0); /* 初始位置,第一张图片在容器最左边 */
}
100% {
/* 关键:动画结束位置,将图片列表向左移动,直到第一张图片的副本完全进入容器,
同时原始的第一张图片完全移出容器左侧,移动距离就是一张图片的宽度。 */
transform: translateX(-300px);
}
}
/* 鼠标悬停时暂停滚动 */
.scroll-container:hover .scroll-content {
animation-play-state: paused;
}
原理详解:
overflow: hidden:这是实现“视口”效果的核心,它告诉浏览器,.scroll-container内部的任何超出其范围的内容都不要显示。display: flex:让所有<img>标签在同一行内水平排列。animation: scroll 20s linear infinite:scroll:我们定义的动画名称。20s:动画持续20秒,你可以根据需要调整。linear:动画速度是均匀的。infinite:动画无限次循环播放。
transform: translateX(-300px):这是动画的终点,它将整个图片列表向左平移了300px(即一张图片的宽度),因为我们在末尾添加了第一张图片的副本,所以当动画执行到这里时,用户看到的是第二张图片无缝地接在了第一张图片的后面,而整个列表又回到了初始位置,等待下一次动画。
使用 JavaScript(更灵活)
如果滚动效果需要更复杂的控制(比如鼠标悬停暂停、点击切换、响应式调整速度等),使用JavaScript会是更好的选择。
核心思路:
- 获取图片列表元素。
- 使用
setInterval定期更新图片列表的transform: translateX属性,实现平滑移动。 - 当滚动到末尾(即第一张图片完全移出视口)时,瞬间将图片列表的位置重置到起点,并移除第一张图片的副本,然后将它追加到末尾,实现无缝循环。
实现代码:
HTML 结构 (与方法一类似,但不需要在HTML中手动添加副本)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">JS 连续滚动图片</title>
<style>
/* CSS 基本样式与方法一相同,但移除 animation 相关代码 */
body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; padding: 20px; }
h1 { color: #333; }
.scroll-container {
width: 800px;
height: 220px;
overflow: hidden;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.scroll-content {
display: flex;
transition: transform 0.5s ease-in-out; /* 添加平滑过渡效果 */
}
.scroll-content img {
width: 300px;
height: 200px;
object-fit: cover;
flex-shrink: 0;
}
</style>
</head>
<body>
<h1>JS 控制的连续滚动图片</h1>
<div class="scroll-container" id="js-scroll-container">
<div class="scroll-content" id="js-scroll-content">
<img src="https://picsum.photos/seed/js1/300/200.jpg" alt="图片 1">
<img src="https://picsum.photos/seed/js2/300/200.jpg" alt="图片 2">
<img src="https://picsum.photos/seed/js3/300/200.jpg" alt="图片 3">
<img src="https://picsum.photos/seed/js4/300/200.jpg" alt="图片 4">
<img src="https://picsum.photos/seed/js5/300/200.jpg" alt="图片 5">
</div>
</div>
<script src="script.js"></script>
</body>
</html>
JavaScript 代码
// script.js
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('js-scroll-container');
const content = document.getElementById('js-scroll-content');
const images = content.getElementsByTagName('img');
const imageWidth = images[0].clientWidth; // 获取第一张图片的宽度
let position = 0;
let animationId;
// 克隆第一张图片并添加到列表末尾,用于无缝循环
const firstImageClone = images[0].cloneNode(true);
content.appendChild(firstImageClone);
function startScrolling() {
// 使用 requestAnimationFrame 实现更流畅的动画
function scroll() {
position -= 1; // 每次向左移动1像素
content.style.transform = `translateX(${position}px)`;
// 检查是否滚动到第一张图片完全离开视口的位置
if (position <= -imageWidth) {
// 瞬间重置位置,但用户无感知
position += imageWidth;
// 将第一张图片移到末尾
content.style.transition = 'none'; // 禁用过渡效果,实现瞬间移动
content.style.transform = `translateX(${position}px)`;
// 强制浏览器重绘,然后恢复过渡效果
void content.offsetWidth;
content.style.transition = 'transform 0.5s ease-in-out';
// 移除第一张原始图片,并将其副本追加到末尾
content.removeChild(images[0]);
content.appendChild(images[0].cloneNode(true));
}
animationId = requestAnimationFrame(scroll);
}
scroll();
}
// 鼠标悬停时暂停
container.addEventListener('mouseenter', () => {
cancelAnimationFrame(animationId);
});
// 鼠标离开时继续
container.addEventListener('mouseleave', () => {
startScrolling();
});
// 开始滚动
startScrolling();
});
使用现成的库(最快,最功能强大)
在实际项目中,我们通常会使用成熟的轮播图库,它们经过充分优化,功能强大且易于使用。

(图片来源网络,侵删)
推荐库:
- Swiper.js: 功能最全面,性能优异,支持触摸滑动、无限循环、分页器、导航按钮等几乎所有你能想到的功能。
- Slick: 非常流行,配置简单,效果炫酷。
使用 Swiper.js 的示例:
引入 Swiper 的 CSS 和 JS 文件
<!-- Swiper CSS --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.css"/> <!-- Swiper JS --> <script src="https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js"></script>
HTML 结构
Swiper 有固定的HTML结构,你需要遵循它。
<div class="swiper mySwiper">
<div class="swiper-wrapper">
<!-- Slide 1 -->
<div class="swiper-slide">
<img src="https://picsum.photos/seed/swiper1/800/400.jpg" alt="Slide 1">
</div>
<!-- Slide 2 -->
<div class="swiper-slide">
<img src="https://picsum.photos/seed/swiper2/800/400.jpg" alt="Slide 2">
</div>
<!-- Slide 3 -->
<div class="swiper-slide">
<img src="https://picsum.photos/seed/swiper3/800/400.jpg" alt="Slide 3">
</div>
<!-- ... more slides ... -->
</div>
<!-- 如果需要分页器 -->
<div class="swiper-pagination"></div>
</div>
初始化 Swiper
在 <script> 标签中初始化你的轮播图。
<script>
document.addEventListener('DOMContentLoaded', () => {
var swiper = new Swiper(".mySwiper", {
loop: true, // 无限循环模式
autoplay: {
delay: 2500, // 自动切换时间
disableOnInteraction: false, // 用户操作后是否停止自动播放
},
pagination: {
el: ".swiper-pagination", // 分页器的选择器
clickable: true, // 点击分页器切换
},
});
});
</script>
总结与选择建议
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
CSS @keyframes |
性能最好,代码简单,纯CSS实现,无依赖。 | 动画控制简单(如暂停/播放),逻辑固定,需要手动处理副本。 | 简单的、不需要交互的图片轮播或新闻滚动条。 |
| JavaScript | 非常灵活,可以添加任意复杂的交互逻辑,动态控制。 | 代码量稍多,需要手动处理DOM操作和动画逻辑。 | 需要复杂控制、响应式行为或与后端数据结合的场景。 |
| 轮播图库 (Swiper) | 功能强大,开箱即用,效果专业,支持触摸、响应式等。 | 引入了外部依赖,会增加页面体积。 | 商业项目、复杂的轮播需求、追求开发效率和用户体验的场景。 |
对于大多数情况,我首推使用方法一(CSS动画),因为它简单、高效且足够满足基本需求,如果项目需要更高级的功能,再考虑使用方法二(JS)或直接集成方法三(库)。
