第一步:设计思路与规划
在敲代码之前,先构思一下我们想要的效果。

(图片来源网络,侵删)
-
主题与风格:
- 主题:街道摄影,图片可以是城市风光、街头巷尾、人文瞬间等。
- 风格:现代、简约、有故事感,可以使用黑白或复古滤镜来增强氛围。
-
核心功能:
- 照片展示:以网格或瀑布流的形式展示缩略图。
- 点击放大:点击任意一张照片,可以在一个模态框(Modal)中查看大图。
- 信息展示:查看大图时,可以显示照片的标题、拍摄地点和描述。
- 导航控制:在模态框中,可以通过左右箭头或键盘方向键切换上一张/下一张照片。
- 关闭功能:点击模态框背景或关闭按钮,退出大图查看模式。
-
页面结构:
- 头部和简短介绍。
- 主体:照片网格展示区。
- 模态框:用于显示大图和照片信息(默认隐藏)。
第二步:准备素材
- 图片:准备一组你的街道摄影作品,建议使用不同尺寸的图片,这样在瀑布流布局中会更有层次感。
- 图标:准备一些简单的图标,如放大镜、关闭按钮、左右箭头等,你可以使用 Font Awesome 这样的图标库,或者直接用SVG代码。
- 文件夹结构:创建一个项目文件夹,并建立如下结构,方便管理文件。
street-album/ ├── index.html ├── css/ │ └── style.css ├── js/ │ └── script.js └── images/ ├── thumbnail/ │ ├── street1.jpg │ ├── street2.jpg │ └── ... └── fullsize/ ├── street1.jpg ├── street2.jpg └── ...
第三步:编写HTML结构 (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>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>
<h1>街道印象</h1>
<p>捕捉城市角落的每一瞬间</p>
</header>
<main id="photo-gallery">
<!-- 照片网格将通过JavaScript动态生成 -->
</main>
<!-- 模态框 -->
<div id="photo-modal" class="modal">
<span class="close-btn">×</span>
<div class="modal-content">
<span class="prev-btn">❮</span>
<img id="modal-img" src="" alt="">
<div id="modal-caption">
<h2 id="modal-title"></h2>
<p id="modal-location"></p>
<p id="modal-description"></p>
</div>
<span class="next-btn">❯</span>
</div>
</div>
<script src="js/script.js"></script>
</body>
</html>
说明:
- 我们使用了一个
<main>容器来放置照片网格,id为photo-gallery。 - 模态框
<div id="photo-modal">默认是隐藏的(通过CSS控制)。 - 引入了 Font Awesome 用于显示图标。
- HTML 结构非常简洁,大部分照片数据将由 JavaScript 动态加载。
第四步:添加CSS样式 (css/style.css)
CSS负责页面的视觉呈现,让相册变得美观。
/* 全局样式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Helvetica Neue', Arial, sans-serif;
background-color: #f4f4f4;
color: #333;
line-height: 1.6;
}
header {
text-align: center;
padding: 2rem 1rem;
background-color: #2c3e50;
color: #ecf0f1;
}
header h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
}
/* 照片网格 */
#photo-gallery {
column-count: 4; /* 创建多列布局 */
column-gap: 1rem; /* 列间距 */
padding: 1rem;
max-width: 1400px;
margin: 0 auto;
}
.photo-item {
break-inside: avoid; /* 防止图片被分割到不同列 */
margin-bottom: 1rem;
cursor: pointer;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.photo-item:hover {
transform: translateY(-5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.photo-item img {
width: 100%;
display: block;
height: auto;
}
/* 模态框样式 */
.modal {
display: none; /* 默认隐藏 */
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.9); /* 半透明黑色背景 */
animation: fadeIn 0.3s ease;
}
.modal-content {
position: relative;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
width: 90%;
max-width: 1000px;
max-height: 90vh;
}
#modal-img {
width: 100%;
max-height: 80vh;
object-fit: contain; /* 保持图片比例 */
}
#modal-caption {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.7);
color: #fff;
padding: 20px;
text-align: center;
}
#modal-caption h2 {
margin-bottom: 10px;
}
/* 按钮样式 */
.close-btn, .prev-btn, .next-btn {
position: absolute;
color: #f1f1f1;
font-size: 40px;
font-weight: bold;
cursor: pointer;
transition: color 0.3s ease;
z-index: 1001;
}
.close-btn {
top: 10px;
right: 25px;
}
.prev-btn {
left: 25px;
top: 50%;
transform: translateY(-50%);
}
.next-btn {
right: 25px;
top: 50%;
transform: translateY(-50%);
}
.close-btn:hover, .prev-btn:hover, .next-btn:hover {
color: #bbb;
}
/* 动画效果 */
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* 响应式设计 */
@media (max-width: 1200px) {
#photo-gallery { column-count: 3; }
}
@media (max-width: 768px) {
#photo-gallery { column-count: 2; }
}
@media (max-width: 480px) {
#photo-gallery { column-count: 1; }
}
说明:
- 瀑布流效果:我们使用了
column-count属性来创建多列布局,break-inside: avoid确保每个图片项不会被分割,从而自然形成瀑布流。 - 模态框:使用
position: fixed和z-index使其覆盖整个屏幕。display: none使其默认隐藏。 - 响应式:通过媒体查询(
@media),在不同屏幕尺寸下调整列数,保证在手机和电脑上都有良好的体验。 - 悬停效果:为图片添加了轻微的上浮和阴影效果,提升交互感。
第五步:实现JavaScript交互 (js/script.js)
这是相册的灵魂,负责处理用户点击、显示大图、切换图片等所有动态行为。

(图片来源网络,侵删)
// 照片数据
const photos = [
{
src: 'images/fullsize/street1.jpg',
thumbnail: 'images/thumbnail/street1.jpg',
title: '雨后的胡同',
location: '北京,南锣鼓巷',
description: '雨后的石板路反射着霓虹灯的光芒,充满了生活的气息。'
},
{
src: 'images/fullsize/street2.jpg',
thumbnail: 'images/thumbnail/street2.jpg',
title: '午后的咖啡馆',
location: '上海,武康路',
description: '阳光透过梧桐叶的缝隙,洒在街角的咖啡馆。'
},
{
src: 'images/fullsize/street3.jpg',
thumbnail: 'images/thumbnail/street3.jpg',
title: '都市的脉搏',
location: '香港,旺角',
description: '川流不息的人群,是这座城市永不停止的脉搏。'
},
// 在这里继续添加更多照片数据...
{
src: 'images/fullsize/street4.jpg',
thumbnail: 'images/thumbnail/street4.jpg',
title: '转角遇到爱',
location: '成都,宽窄巷子',
description: '不经意的转角,总能发现意想不到的美好。'
},
{
src: 'images/fullsize/street5.jpg',
thumbnail: 'images/thumbnail/street5.jpg',
title: '孤独的守望者',
location: '西安,钟楼',
description: '古老的建筑静静矗立,见证了城市的变迁。'
}
];
// 获取DOM元素
const gallery = document.getElementById('photo-gallery');
const modal = document.getElementById('photo-modal');
const modalImg = document.getElementById('modal-img');
const modalTitle = document.getElementById('modal-title');
const modalLocation = document.getElementById('modal-location');
const modalDescription = document.getElementById('modal-description');
const closeBtn = document.querySelector('.close-btn');
const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
let currentPhotoIndex = 0;
// 生成照片网格
function generateGallery() {
photos.forEach((photo, index) => {
const photoItem = document.createElement('div');
photoItem.className = 'photo-item';
photoItem.innerHTML = `<img src="${photo.thumbnail}" alt="${photo.title}">`;
photoItem.addEventListener('click', () => openModal(index));
gallery.appendChild(photoItem);
});
}
// 打开模态框
function openModal(index) {
currentPhotoIndex = index;
const photo = photos[index];
modal.style.display = 'block';
modalImg.src = photo.src;
modalTitle.textContent = photo.title;
modalLocation.textContent = photo.location;
modalDescription.textContent = photo.description;
}
// 关闭模态框
function closeModal() {
modal.style.display = 'none';
}
// 显示上一张
function showPrevPhoto() {
currentPhotoIndex = (currentPhotoIndex - 1 + photos.length) % photos.length;
updateModalContent();
}
// 显示下一张
function showNextPhoto() {
currentPhotoIndex = (currentPhotoIndex + 1) % photos.length;
updateModalContent();
}
// 更新模态框内容
function updateModalContent() {
const photo = photos[currentPhotoIndex];
modalImg.src = photo.src;
modalTitle.textContent = photo.title;
modalLocation.textContent = photo.location;
modalDescription.textContent = photo.description;
}
// 事件监听器
closeBtn.addEventListener('click', closeModal);
prevBtn.addEventListener('click', showPrevPhoto);
nextBtn.addEventListener('click', showNextPhoto);
// 点击模态框背景关闭
modal.addEventListener('click', (e) => {
if (e.target === modal) {
closeModal();
}
});
// 键盘事件监听
document.addEventListener('keydown', (e) => {
if (modal.style.display === 'block') {
if (e.key === 'Escape') {
closeModal();
} else if (e.key === 'ArrowLeft') {
showPrevPhoto();
} else if (e.key === 'ArrowRight') {
showNextPhoto();
}
}
});
// 初始化相册
generateGallery();
说明:
- 数据驱动:我们使用一个
photos数组来存储所有照片的信息,这使得未来添加新照片变得非常简单,只需修改这个数组即可,无需改动HTML结构。 - 动态生成:
generateGallery函数遍历photos数组,为每张照片创建一个<div>元素,并添加到gallery中。 - 事件处理:
- 点击缩略图时,调用
openModal()并传入当前照片的索引。 - 点击关闭按钮、背景或按
ESC键,调用closeModal()。 - 点击左右箭头或按键盘方向键,调用
showPrevPhoto()/showNextPhoto()来切换照片。 - 使用
updateModalContent()来更新模态框中的图片和信息,避免代码重复。
- 点击缩略图时,调用
第六步:美化与进阶
你已经拥有一个功能完整的相册了!如果想让它更上一层楼,可以尝试以下进阶技巧:
-
懒加载:对于大量图片,可以使用
loading="lazy"属性在HTML中实现简单的懒加载,或者使用 Intersection Observer API 来更精确地控制图片加载时机,提升页面初始加载速度。<img src="thumbnail.jpg" loading="lazy" alt="...">
-
滤镜效果:在CSS中可以为图片添加滤镜,营造不同的氛围。
.photo-item img { filter: grayscale(100%); /* 黑白效果 */ transition: filter 0.3s ease; } .photo-item:hover img { filter: grayscale(0%); /* 鼠标悬停时恢复彩色 */ } -
加载动画:在图片加载完成前,可以显示一个加载中的动画或占位符,提升用户体验。
-
图片分类/筛选:如果照片很多,可以增加一个导航栏,让用户按“地点”、“年份”等分类筛选照片,这需要更复杂的JavaScript逻辑,但会让你的相册更专业。
-
全屏模式:在查看大图时,可以添加一个“进入全屏”的按钮,提供更沉浸的观看体验。
通过以上六个步骤,你成功地从零开始创建了一个功能完善、设计精美的HTML街道主题网页相册模板,这个模板不仅展示了你的摄影作品,也体现了你的前端开发能力。
你可以基于这个模板进行二次开发,添加更多个性化功能,打造出属于你自己的独特相册网站,祝你玩得开心!
