完成并交付城市漫游网站
前面十三章一直在修改同一个项目。现在把零散成果整理成一份可以检查、可以交给别人打开的多页面网站。你会看到四个页面的完整代码,也会完成资源、链接、表单、键盘和验证器检查。
先核对最终目录
项目目录应该接近下面的结构:
city-walk/
├── index.html
├── routes.html
├── schedule.html
├── contact.html
├── images/
│ ├── favicon.png
│ ├── river-walk.jpg
│ ├── old-town.jpg
│ └── route-video-cover.jpg
└── media/
├── canal-guide.mp3
├── canal-guide.ogg
├── route-preview.mp4
├── route-preview.webm
└── captions-zh.vtt
图片和媒体文件请换成你有权使用的内容。如果暂时只有一种音频或视频格式,可以删除不存在的 source,不要保留会产生 404 的路径。
完成首页 index.html
首页说明网站主题,提供主要路线入口,并保留一条清楚的报名路径。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta
name="description"
content="城市漫游指南提供可在一天内完成的河岸、老街和公园步行路线。"
>
<title>城市漫游指南|周末步行路线</title>
<link rel="icon" href="images/favicon.png" type="image/png">
</head>
<body>
<a href="#main-content">跳到主要内容</a>
<header>
<p>城市漫游指南</p>
<nav aria-label="主要导航">
<ul>
<li><a href="index.html" aria-current="page">首页</a></li>
<li><a href="routes.html">路线</a></li>
<li><a href="schedule.html">行程</a></li>
<li><a href="contact.html">报名</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<h1>用一天时间,重新认识这座城市</h1>
<p>从河岸、老街到公园,我们把相邻地点串成真正能走完的路线。</p>
<p>
下次活动时间:
<time datetime="2026-08-16T09:00">8 月 16 日上午 9 点</time>
</p>
<p><a href="contact.html">报名参加下一次漫游</a></p>
<section aria-labelledby="featured-title">
<h2 id="featured-title">本周推荐</h2>
<article class="route-card" data-route-id="canal">
<h3>运河慢行线</h3>
<p>全程约 4 公里,中途有两处休息点,适合第一次参加的人。</p>
<a href="routes.html#canal-route">查看运河路线</a>
</article>
<article class="route-card" data-route-id="old-town">
<h3>老街寻味线</h3>
<p>从南门进入,经过茶铺、粮仓和钟楼,中午可以自由用餐。</p>
<a href="routes.html#old-town-route">查看老街路线</a>
</article>
</section>
<aside aria-labelledby="notice-title">
<h2 id="notice-title">出发前提醒</h2>
<p><strong>请在出发前一天完成报名。</strong>雨天石板路较滑,请准备防滑鞋。</p>
</aside>
</main>
<footer>
<address>
集合点:运河游客中心<br>
联系邮箱:<a href="mailto:walk@example.com">walk@example.com</a>
</address>
<p><small>© 2026 城市漫游指南</small></p>
</footer>
</body>
</html>
完成路线页 routes.html
路线页综合使用图片、列表、描述列表、音视频和 iframe。示例地图 URL 可以替换为你所在城市的官方嵌入地址。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta
name="description"
content="查看城市漫游路线的距离、预计用时、经过地点、图片和出发提醒。"
>
<title>漫游路线|城市漫游指南</title
字幕文件 media/captions-zh.vtt 可以从下面的最小版本开始:
WEBVTT
00:00:00.000 --> 00:00:03.500
这里是游客中心,也是路线的集合点。
00:00:03.500 --> 00:00:07.000
出发后沿右侧河岸步道向北行走。
完成行程页 schedule.html
行程页保持专注,只呈现说明和表格。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta
name="description"
content="查看运河慢行线从集合到结束的时间、地点和活动安排。"
>
<title>一日行程|城市漫游指南</title
这仍然是一份静态表单。要真正保存报名,需要把 action 指向你自己的服务器接口,并在服务器端再次验证所有字段。
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta
name="description"
content="填写城市漫游活动报名信息,选择日期、路线和同行人数。"
>
<title>报名参加|城市漫游指南</title
按固定顺序验收项目
从 index.html 开始,不要跳着检查:
双击首页并刷新。确认页面标题、中文、主标题和正文都正常,再依次点击导航打开另外三个页面。
从每个页面返回首页,并检查当前页面的导航链接是否正确使用 aria-current="page"。页面内的路线锚点也要逐个点击。
打开开发者工具的“网络”面板刷新路线页。修复所有本地图片、音频、视频、字幕和图标的 404。暂时没有的格式应从代码中删除。
只用键盘完成导航和表单填写。点击每个可见标签,确认它能聚焦对应控件;不填写必填项提交,确认浏览器会提示。
判断你是否已经学会 HTML
完成课程不等于背出所有标签。更实际的标准是:面对一份内容,你能根据含义选择结构,能查文档补足不常用属性,也能通过浏览器和验证器定位错误。
你现在应该能够独立完成这些任务:
- 从空文件写出完整文档骨架,并解释
head 与 body 的区别。
- 使用标题、段落、列表和语义区块建立清楚层级。
- 使用相对路径连接页面和本地资源。
- 为图片写有用的替代文本,为表格关联行列表头。
- 创建带标签、字段名和基础验证的表单。
- 为音视频提供控制、后备内容和字幕,为 iframe 提供标题和最小权限。
- 检查重复
id、错误嵌套、404 和键盘操作问题。
到这里,城市漫游指南已经从一个空的 index.html 变成了四页完整网站。接下来学习 CSS 时,不需要推翻这些结构;你会在这副正确的 HTML 骨架上增加布局、颜色、间距和响应式样式。
如果你想再做一次真正独立的练习,不要复制本项目文字。保留同样的技术要求,把主题换成读书会、个人简历或旅行计划,从空目录重新完成一遍。能在新内容上做出同样清楚的结构,才说明这些方法已经变成了你的能力。
>
<link rel="icon" href="images/favicon.png" type="image/png">
</head>
<body>
<a href="#main-content">跳到主要内容</a>
<header>
<p>城市漫游指南</p>
<nav aria-label="主要导航">
<ul>
<li><a href="index.html">首页</a></li>
<li><a href="routes.html" aria-current="page">路线</a></li>
<li><a href="schedule.html">行程</a></li>
<li><a href="contact.html">报名</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<h1>漫游路线</h1>
<p>先看路线简介,再根据距离和路况选择适合自己的路线。</p>
<nav aria-label="本页路线">
<ul>
<li><a href="#canal-route">运河慢行线</a></li>
<li><a href="#old-town-route">老街寻味线</a></li>
<li><a href="#route-map">路线地图</a></li>
</ul>
</nav>
<article id="canal-route" class="route-detail" data-distance-km="4">
<h2>运河慢行线</h2>
<figure>
<img
src="images/river-walk.jpg"
alt="傍晚的河岸步道,右侧有连续的石栏杆"
width="960"
height="640"
>
<figcaption>全程约 4 公里,沿途有两处公共休息点。</figcaption>
</figure>
<h3>经过地点</h3>
<ol>
<li>在游客中心签到并领取路线卡。</li>
<li>沿河向北走到旧码头。</li>
<li>穿过石桥,在粮仓广场休息。</li>
<li>从公园南门结束行程。</li>
</ol>
<h3>路线信息</h3>
<dl>
<dt>距离</dt>
<dd>约 4 公里</dd>
<dt>预计用时</dt>
<dd>2.5 小时</dd>
<dt>难度</dt>
<dd>平缓</dd>
</dl>
<h3>建议携带</h3>
<ul>
<li>500 毫升以上饮用水</li>
<li>雨具或遮阳帽</li>
<li>充满电的手机</li>
</ul>
</article>
<article id="old-town-route" class="route-detail" data-distance-km="3.2">
<h2>老街寻味线</h2>
<figure>
<img
src="images/old-town.jpg"
alt="青石路两侧保留着木结构店铺"
width="960"
height="640"
>
<figcaption>从南门进入,上午人少,适合作为路线起点。</figcaption>
</figure>
<p><mark>东入口施工,请从南门进入。</mark></p>
<ol>
<li>老街南门</li>
<li>百年茶铺</li>
<li>旧粮仓</li>
<li>钟楼广场</li>
</ol>
</article>
<section aria-labelledby="audio-title">
<h2 id="audio-title">出发前先听一段讲解</h2>
<p>音频介绍集合点和前 500 米的路况。</p>
<audio controls preload="metadata">
<source src="media/canal-guide.mp3" type="audio/mpeg">
<source src="media/canal-guide.ogg" type="audio/ogg">
<p><a href="media/canal-guide.mp3">下载讲解音频</a></p>
</audio>
</section>
<section aria-labelledby="video-title">
<h2 id="video-title">路线入口视频</h2>
<video
controls
preload="metadata"
poster="images/route-video-cover.jpg"
width="960"
height="540"
>
<source src="media/route-preview.mp4" type="video/mp4">
<source src="media/route-preview.webm" type="video/webm">
<track
src="media/captions-zh.vtt"
kind="captions"
srclang="zh-CN"
label="简体中文"
default
>
<p><a href="media/route-preview.mp4">下载路线预览</a></p>
</video>
</section>
<section id="route-map" aria-labelledby="map-title">
<h2 id="map-title">路线地图</h2>
<p>地图标出了运河附近区域。发布前请换成你的真实路线。</p>
<iframe
src="https://www.openstreetmap.org/export/embed.html?bbox=120.13%2C30.25%2C120.18%2C30.29&layer=mapnik"
title="运河慢行线地图"
width="960"
height="540"
loading="lazy"
referrerpolicy="strict-origin-when-cross-origin"
></iframe>
<p>
<a href="https://www.openstreetmap.org/?mlat=30.27&mlon=120.155#map=14/30.27/120.155">
在新页面查看地图
</a>
</p>
</section>
</main>
<footer>
<address>
集合点:运河游客中心<br>
联系邮箱:<a href="mailto:walk@example.com">walk@example.com</a>
</address>
<p><small>© 2026 城市漫游指南</small></p>
</footer>
</body>
</html>
>
<link rel="icon" href="images/favicon.png" type="image/png">
</head>
<body>
<a href="#main-content">跳到主要内容</a>
<header>
<p>城市漫游指南</p>
<nav aria-label="主要导航">
<ul>
<li><a href="index.html">首页</a></li>
<li><a href="routes.html">路线</a></li>
<li><a href="schedule.html" aria-current="page">行程</a></li>
<li><a href="contact.html">报名</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<h1>一日行程</h1>
<p>以下时间可能因天气和步行速度略有调整。</p>
<table>
<caption>运河慢行线周六行程</caption>
<thead>
<tr>
<th scope="col">时间</th>
<th scope="col">地点</th>
<th scope="col">安排</th>
<th scope="col">提醒</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row"><time datetime="09:00">09:00</time></th>
<td>游客中心</td>
<td>签到和安全说明</td>
<td>请提前 10 分钟到达</td>
</tr>
<tr>
<th scope="row"><time datetime="09:30">09:30</time></th>
<td>河岸步道</td>
<td>开始步行</td>
<td>沿右侧步道前进</td>
</tr>
<tr>
<th scope="row"><time datetime="10:15">10:15</time></th>
<td>旧码头</td>
<td>讲解和自由拍照</td>
<td>停留约 30 分钟</td>
</tr>
<tr>
<th scope="row"><time datetime="11:30">11:30</time></th>
<td>公园南门</td>
<td>结束行程</td>
<td>可自行继续游览</td>
</tr>
</tbody>
<tfoot>
<tr>
<th scope="row" colspan="2">预计总时长</th>
<td colspan="2">约 2.5 小时</td>
</tr>
</tfoot>
</table>
<p><a href="contact.html">确认时间后前往报名</a></p>
</main>
<footer>
<address>
集合点:运河游客中心<br>
联系邮箱:<a href="mailto:walk@example.com">walk@example.com</a>
</address>
<p><small>© 2026 城市漫游指南</small></p>
</footer>
</body>
</html>
>
<link rel="icon" href="images/favicon.png" type="image/png">
</head>
<body>
<a href="#main-content">跳到主要内容</a>
<header>
<p>城市漫游指南</p>
<nav aria-label="主要导航">
<ul>
<li><a href="index.html">首页</a></li>
<li><a href="routes.html">路线</a></li>
<li><a href="schedule.html">行程</a></li>
<li><a href="contact.html" aria-current="page">报名</a></li>
</ul>
</nav>
</header>
<main id="main-content">
<h1>报名参加</h1>
<p>带星号的项目为必填项。提交前请再次核对邮箱。</p>
<form action="" method="post">
<p>
<label for="full-name">姓名 *</label>
<input
id="full-name"
name="fullName"
type="text"
autocomplete="name"
required
>
</p>
<p>
<label for="email">邮箱 *</label>
<input
id="email"
name="email"
type="email"
autocomplete="email"
required
>
</p>
<p>
<label for="walk-date">参加日期 *</label>
<input id="walk-date" name="walkDate" type="date" required>
</p>
<fieldset>
<legend>选择路线 *</legend>
<label>
<input type="radio" name="route" value="canal" required>
运河慢行线
</label>
<label>
<input type="radio" name="route" value="old-town">
老街寻味线
</label>
</fieldset>
<p>
<label for="group-size">同行人数 *</label>
<select id="group-size" name="groupSize" required>
<option value="">请选择</option>
<option value="1">1 人</option>
<option value="2">2 人</option>
<option value="3">3 人</option>
<option value="4">4 人</option>
</select>
</p>
<fieldset>
<legend>需要的协助</legend>
<label>
<input type="checkbox" name="support" value="slow-pace">
需要慢速队伍
</label>
<label>
<input type="checkbox" name="support" value="large-print">
需要大字版路线卡
</label>
</fieldset>
<p>
<label for="note">补充说明</label>
<textarea id="note" name="note" rows="5" maxlength="300"></textarea>
</p>
<p>
<label>
<input type="checkbox" name="agreement" value="accepted" required>
我已阅读路线说明,并确认身体状况适合步行。*
</label>
</p>
<button type="submit">提交报名</button>
</form>
</main>
<footer>
<address>
集合点:运河游客中心<br>
联系邮箱:<a href="mailto:walk@example.com">walk@example.com</a>
</address>
<p><small>© 2026 城市漫游指南</small></p>
</footer>
</body>
</html>
检查窄窗口下是否仍能阅读内容。HTML 已提供正确视口,但宽表格和视频的响应式外观要在 CSS 课程中继续处理。
把四个文件分别交给 HTML 验证器。先修复结构错误,再处理重复 id、无效属性和缺少的替代文本。
完成并交付城市漫游网站 | 自在学