- 响应式设计:在手机、平板和电脑上都能良好显示。
- 核心功能:
- 缩略图导航:点击缩略图可以快速切换主图。
- 左右箭头:浏览上一张/下一张照片。
- 图片计数器:显示当前是第几张图片(3 / 8)。
- 平滑过渡:图片切换时有淡入淡出的动画效果。
- 高级特效:
- 自动播放/暂停:鼠标悬停在相册上时暂停自动播放。
- 键盘控制:使用键盘左右箭头键也可以切换图片。
- 放大镜特效:鼠标悬停在主图上时,可以查看图片的放大细节。
最终效果预览
第一步:HTML 结构
我们需要创建相册的基本HTML结构,我们将使用一个主容器来包裹所有元素,包括一张主图、导航箭头、计数器和缩略图列表。

(图片来源网络,侵删)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">CSS & JS 动态相册</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="gallery-container">
<!-- 主图区域 -->
<div class="main-image-container">
<img id="mainImage" src="https://picsum.photos/seed/img1/800/500.jpg" alt="主图">
<!-- 放大镜效果层 -->
<div class="magnifier-glass"></div>
<!-- 左右箭头 -->
<button class="nav-btn prev-btn">❮</button>
<button class="nav-btn next-btn">❯</button>
<!-- 图片计数器 -->
<div class="image-counter">
<span id="currentIndex">1</span> / <span id="totalImages">8</span>
</div>
</div>
<!-- 缩略图导航区域 -->
<div class="thumbnail-list">
<!-- 缩略图将通过JS动态生成 -->
</div>
</div>
<script src="script.js"></script>
</body>
</html>
代码说明:
gallery-container: 整个相册的包裹容器。main-image-container: 主图的显示区域,包含所有相关控件。mainImage: 用于显示当前选中的大图。magnifier-glass: 用于实现放大镜效果的可视层。nav-btn: 左右导航按钮。image-counter: 显示图片序号的计数器。thumbnail-list: 缩略图的列表容器,初始为空,将由JS填充。
第二步:CSS 样式
我们使用CSS来美化相册,并添加过渡动画和放大镜特效的样式。
/* style.css */
body {
font-family: 'Arial', sans-serif;
background-color: #f0f2f5;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
}
.gallery-container {
max-width: 900px;
width: 100%;
background-color: #fff;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
border-radius: 12px;
overflow: hidden;
}
/* 主图区域样式 */
.main-image-container {
position: relative;
width: 100%;
height: 500px;
overflow: hidden;
}
#mainImage {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
transition: opacity 0.5s ease-in-out; /* 图片切换的淡入淡出效果 */
}
/* 导航按钮样式 */
.nav-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: rgba(0, 0, 0, 0.5);
color: white;
border: none;
font-size: 2rem;
padding: 15px 20px;
cursor: pointer;
border-radius: 50%;
transition: background-color 0.3s ease, transform 0.2s ease;
z-index: 10;
}
.nav-btn:hover {
background-color: rgba(0, 0, 0, 0.8);
}
.prev-btn {
left: 20px;
}
.next-btn {
right: 20px;
}
/* 图片计数器样式 */
.image-counter {
position: absolute;
bottom: 20px;
right: 20px;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px 15px;
border-radius: 20px;
font-size: 0.9rem;
z-index: 10;
}
/* 缩略图列表样式 */
.thumbnail-list {
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
gap: 15px;
flex-wrap: wrap; /* 在小屏幕上自动换行 */
background-color: #fafafa;
}
.thumbnail {
width: 80px;
height: 60px;
object-fit: cover;
border-radius: 8px;
cursor: pointer;
opacity: 0.6;
transition: opacity 0.3s ease, transform 0.2s ease, border 0.3s ease;
border: 2px solid transparent;
}
.thumbnail:hover {
opacity: 0.8;
transform: scale(1.05);
}
.thumbnail.active {
opacity: 1;
border-color: #007bff;
}
/* --- 放大镜特效样式 --- */
.magnifier-glass {
position: absolute;
border: 3px solid #fff;
border-radius: 50%;
cursor: none;
width: 150px;
height: 150px;
display: none; /* 默认隐藏 */
box-shadow: 0 0 20px rgba(0, 0, 0, 0.4);
pointer-events: none; /* 确保鼠标事件能穿透到下面的图片 */
}
/* 响应式设计 */
@media (max-width: 768px) {
.main-image-container {
height: 350px;
}
.thumbnail {
width: 60px;
height: 45px;
}
.nav-btn {
font-size: 1.5rem;
padding: 10px 15px;
}
}
代码说明:
#mainImage的transition: opacity: 这是实现图片淡入淡出的关键,当src属性改变时,浏览器会先加载新图片,加载完成后,通过改变opacity来实现平滑过渡。.thumbnail的active类: 用于高亮显示当前选中的缩略图。.magnifier-glass: 这是放大镜的“镜片”,它被设置为绝对定位,默认隐藏,pointer-events: none确保它不会干扰鼠标与主图的交互。- 响应式媒体查询 (
@media): 在小屏幕设备上,调整相册高度、缩略图大小和导航按钮大小,以获得更好的用户体验。
第三步:JavaScript 特效
我们用JavaScript来实现所有的交互逻辑,包括图片切换、自动播放、键盘控制和放大镜效果。

(图片来源网络,侵删)
// script.js
document.addEventListener('DOMContentLoaded', () => {
// --- 1. 获取DOM元素 ---
const mainImage = document.getElementById('mainImage');
const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const currentIndexSpan = document.getElementById('currentIndex');
const totalImagesSpan = document.getElementById('totalImages');
const thumbnailList = document.querySelector('.thumbnail-list');
const magnifierGlass = document.querySelector('.magnifier-glass');
// --- 2. 图片数据 ---
// 使用 picsum.photos 服务生成不同的图片
const images = [
{ src: 'https://picsum.photos/seed/img1/800/500.jpg', thumb: 'https://picsum.photos/seed/img1/80/60.jpg' },
{ src: 'https://picsum.photos/seed/img2/800/500.jpg', thumb: 'https://picsum.photos/seed/img2/80/60.jpg' },
{ src: 'https://picsum.photos/seed/img3/800/500.jpg', thumb: 'https://picsum.photos/seed/img3/80/60.jpg' },
{ src: 'https://picsum.photos/seed/img4/800/500.jpg', thumb: 'https://picsum.photos/seed/img4/80/60.jpg' },
{ src: 'https://picsum.photos/seed/img5/800/500.jpg', thumb: 'https://picsum.photos/seed/img5/80/60.jpg' },
{ src: 'https://picsum.photos/seed/img6/800/500.jpg', thumb: 'https://picsum.photos/seed/img6/80/60.jpg' },
{ src: 'https://picsum.photos/seed/img7/800/500.jpg', thumb: 'https://picsum.photos/seed/img7/80/60.jpg' },
{ src: 'https://picsum.photos/seed/img8/800/500.jpg', thumb: 'https://picsum.photos/seed/img8/80/60.jpg' }
];
let currentIndex = 0;
let autoPlayInterval;
// --- 3. 初始化函数 ---
function init() {
// 设置总图片数
totalImagesSpan.textContent = images.length;
// 生成缩略图
images.forEach((image, index) => {
const img = document.createElement('img');
img.src = image.thumb;
img.alt = `缩略图 ${index + 1}`;
img.classList.add('thumbnail');
if (index === 0) img.classList.add('active'); // 第一张默认激活
img.addEventListener('click', () => showImage(index));
thumbnailList.appendChild(img);
});
// 绑定事件监听器
prevBtn.addEventListener('click', showPrevImage);
nextBtn.addEventListener('click', showNextImage);
// 键盘控制
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') showPrevImage();
if (e.key === 'ArrowRight') showNextImage();
});
// 鼠标悬停事件(自动播放/暂停)
const mainImageContainer = document.querySelector('.main-image-container');
mainImageContainer.addEventListener('mouseenter', stopAutoPlay);
mainImageContainer.addEventListener('mouseleave', startAutoPlay);
// 放大镜事件
mainImageContainer.addEventListener('mouseenter', startMagnifier);
mainImageContainer.addEventListener('mouseleave', stopMagnifier);
mainImageContainer.addEventListener('mousemove', moveMagnifier);
// 启动自动播放
startAutoPlay();
}
// --- 4. 核心功能函数 ---
function showImage(index) {
// 移除所有缩略图的active类
document.querySelectorAll('.thumbnail').forEach(thumb => thumb.classList.remove('active'));
// 添加active类到当前缩略图
document.querySelectorAll('.thumbnail')[index].classList.add('active');
// 更新计数器
currentIndexSpan.textContent = index + 1;
// 更新主图
mainImage.style.opacity = 0; // 先淡出
setTimeout(() => {
mainImage.src = images[index].src;
mainImage.style.opacity = 1; // 再淡入
}, 500); // 与CSS中的过渡时间匹配
currentIndex = index;
}
function showPrevImage() {
const newIndex = (currentIndex - 1 + images.length) % images.length;
showImage(newIndex);
}
function showNextImage() {
const newIndex = (currentIndex + 1) % images.length;
showImage(newIndex);
}
// --- 5. 自动播放功能 ---
function startAutoPlay() {
autoPlayInterval = setInterval(showNextImage, 3000); // 每3秒切换一次
}
function stopAutoPlay() {
clearInterval(autoPlayInterval);
}
// --- 6. 放大镜特效 ---
function startMagnifier() {
magnifierGlass.style.display = "block";
}
function stopMagnifier() {
magnifierGlass.style.display = "none";
}
function moveMagnifier(e) {
const mainImageContainer = document.querySelector('.main-image-container');
const rect = mainImageContainer.getBoundingClientRect();
// 计算鼠标在容器内的相对位置
let x = e.clientX - rect.left;
let y = e.clientY - rect.top;
// 防止放大镜移出容器边界
if (x > mainImage.width - magnifierGlass.offsetWidth / 2) {
x = mainImage.width - magnifierGlass.offsetWidth / 2;
}
if (x < magnifierGlass.offsetWidth / 2) {
x = magnifierGlass.offsetWidth / 2;
}
if (y > mainImage.height - magnifierGlass.offsetHeight / 2) {
y = mainImage.height - magnifierGlass.offsetHeight / 2;
}
if (y < magnifierGlass.offsetHeight / 2) {
y = magnifierGlass.offsetHeight / 2;
}
// 设置放大镜的位置
magnifierGlass.style.left = (x - magnifierGlass.offsetWidth / 2) + "px";
magnifierGlass.style.top = (y - magnifierGlass.offsetHeight / 2) + "px";
// 计算背景图片的位置,实现放大效果
const bgX = -(x * 2 - magnifierGlass.offsetWidth / 2);
const bgY = -(y * 2 - magnifierGlass.offsetHeight / 2);
magnifierGlass.style.backgroundImage = `url(${mainImage.src})`;
magnifierGlass.style.backgroundRepeat = "no-repeat";
magnifierGlass.style.backgroundSize = `${mainImage.width * 2}px ${mainImage.height * 2}px`; // 放大2倍
magnifierGlass.style.backgroundPosition = `${bgX}px ${bgY}px`;
}
// 启动应用
init();
});
代码说明:
- 数据结构 (
images数组): 将图片的大图地址和小图地址存储在一个对象数组中,方便管理。 showImage(index)函数: 这是相册的核心,它负责更新缩略图的高亮状态、计数器,并通过先设置opacity:0,再改变src,最后恢复opacity:1的方式,实现平滑的淡入淡出切换效果。- 自动播放: 使用
setInterval定时调用showNextImage,当鼠标悬停在相册上时,用clearInterval清除定时器来暂停播放;鼠标离开时重新启动。 - 键盘控制: 监听
keydown事件,当按下左右箭头键时,触发相应的图片切换函数。 - 放大镜特效:
startMagnifier/stopMagnifier: 控制放大镜镜片的显示与隐藏。moveMagnifier: 在鼠标移动时被调用,它计算鼠标位置,设置放大镜镜片的位置,并巧妙地使用background-image、background-size和background-position来创建一个放大2倍的局部视图。background-size是原图的2倍,而background-position则根据鼠标位置反向移动,从而产生“放大镜跟随鼠标”的视觉效果。
如何使用
- 将上面三个代码块分别保存为
index.html、style.css和script.js文件。 - 将这三个文件放在同一个文件夹中。
- 用浏览器打开
index.html文件,即可看到动态相册的效果。
您可以根据需要轻松地修改 images 数组来替换您自己的图片,或者通过调整CSS中的数值来改变相册的外观、动画速度和放大倍率。

(图片来源网络,侵删)
