没问题!下面把“高亮功能加之前”的 Navbar 最小示例(index.html / nav.css / nav.js)逐行加注释,便于带零基础学生理解。随后给出一份术语词汇表,并用本例逐条解释这些术语。
index.html<!doctype html> <!-- 声明 HTML5 文档类型,启用标准模式 -->
<html lang="zh-CN"> <!-- 根元素,lang 指明页面语言为简体中文 -->
<head> <!-- 文档头部:放元数据、标题、外链样式等 -->
<meta charset="utf-8" /> <!-- 设置字符编码为 UTF-8,避免中文乱码 -->
<meta name="viewport" content="width=device-width, initial-scale=1" /> <!-- 视口设置:移动端按设备宽度排版,初始缩放 1 -->
<title>MVB 博客 · 导航栏演示</title> <!-- 浏览器标签上的标题 -->
<link rel="stylesheet" href="nav.css" /> <!-- 外部样式表,负责页面样式 -->
</head>
<body> <!-- 页面主体内容开始 -->
<header class="site-header"> <!-- 语义化页眉区域,承载 Logo 与主导航 -->
<a class="logo" href="index.html">MyBlog</a> <!-- 网站标识:点击返回首页 -->
<button class="nav-toggle" aria-expanded="false" aria-controls="site-nav" aria-label="切换导航"> <!-- 移动端汉堡按钮 -->
☰ <!-- 按钮可见文本:三横“汉堡”符号 -->
</button>
<nav id="site-nav" class="nav" aria-label="主导航"> <!-- 主导航,aria-label 便于屏幕阅读器识别 -->
<ul> <!-- 无序列表,承载多个导航项 -->
<li><a href="index.html">首页</a></li> <!-- 导航项:首页 -->
<li><a href="post.html">文章</a></li> <!-- 导航项:文章列表/详情占位 -->
<li><a href="about.html">关于</a></li> <!-- 导航项:关于页 -->
<li><a href="contact.html">联系</a></li> <!-- 导航项:联系页 -->
</ul>
</nav>
</header>
<main class="container"> <!-- 页面主内容区域 -->
<h1>欢迎来到最小可用博客</h1> <!-- 主标题 -->
<p>这是导航栏组件的演示页。</p> <!-- 简要说明文本 -->
</main>
<script src="nav.js"></script> <!-- 外部脚本,负责交互(汉堡按钮等) -->
</body>
</html>
nav.css* { box-sizing: border-box; } /* 盒模型以边框为界计算宽高,便于布局可控 */
body { margin: 0; font-family: system-ui, -apple-system, "Segoe UI", Arial, "Noto Sans SC"; } /* 去除默认外边距,设置系统字体族 */
.site-header { /* 页眉容器:水平分布 Logo、按钮、导航 */
display: flex; /* Flexbox 弹性布局,子元素在主轴上排列 */
align-items: center; /* 交叉轴(垂直方向)居中 */
justify-content: space-between; /* 主轴两端对齐:左放 Logo,右放按钮/导航 */
padding: 12px 16px; /* 内边距,增加可点击/观感空间 */
background: #222; /* 深色背景 */
color: #fff; /* 前景文字白色 */
position: sticky; /* 粘性定位:滚动到顶后吸附 */
top: 0; /* 吸附到视口顶部 */
}
.logo { color: #fff; text-decoration: none; font-weight: 700; } /* Logo 链接风格 */
.nav-toggle { /* “汉堡按钮”默认隐藏(桌面端不需要) */
display: none; /* 不显示 */
font-size: 20px; /* 字体变大,便于触达 */
background: none; border: 0; color: #fff; /* 按钮基础视觉 */
}
.nav ul { /* 导航列表容器(桌面端水平排列) */
list-style: none; /* 去掉列表圆点 */
display: flex; /* 水平排布 */
gap: 16px; /* 导航项之间的间距 */
margin: 0; padding: 0; /* 去掉默认外/内边距 */
}
.nav a { /* 导航链接的基础视觉样式 */
color: #fff; /* 白色文字 */
text-decoration: none; /* 去掉下划线 */
padding: 8px 10px; /* 点击热区更大,可用性更好 */
border-radius: 6px; /* 圆角,提升观感 */
}
.nav a:hover, .nav a:focus { /* 悬停或键盘聚焦时的反馈 */
background: rgba(255,255,255,.12); /* 半透明高亮 */
outline: none; /* 取消默认描边(配合自定义状态) */
}
/* 移动端折叠:小于等于 768px 屏幕时生效 */
@media (max-width: 768px) {
.nav-toggle { display: inline-block; } /* 显示汉堡按钮 */
.nav { /* 折叠后的菜单面板(初始隐藏) */
position: absolute; left: 0; right: 0; top: 56px; /* 覆盖在页眉下方 */
background: #222; display: none; /* 初始不显示 */
}
.nav.open { display: block; } /* JS 切换 .open 类名后显示面板 */
.nav ul { flex-direction: column; padding: 8px; } /* 垂直排列菜单项 */
.nav a { display: block; } /* 链接铺满一行,便于触达 */
}
.container { padding: 24px; } /* 主内容留出内边距,避免紧贴边缘 */
nav.js// 选中“汉堡按钮”与导航面板
const btn = document.querySelector('.nav-toggle'); // querySelector:用 CSS 选择器选取第一个匹配的元素
const nav = document.getElementById('site-nav'); // 通过 id 获取导航面板元素
// 绑定点击事件:切换导航显隐
btn.addEventListener('click', () => { // addEventListener:为元素注册“点击”事件
const isOpen = nav.classList.toggle('open'); // classList.toggle:有则去掉,无则添加(切换 .open)
btn.setAttribute('aria-expanded', String(isOpen)); // 可访问性:同步按钮“展开状态” true/false
});
// 键盘增强:按 Esc 关闭导航
document.addEventListener('keydown', (e) => { // 在文档级监听键盘按键
if (e.key === 'Escape') { // 判断是否按下 Esc
nav.classList.remove('open'); // 移除 .open,关闭菜单
btn.setAttribute('aria-expanded', 'false'); // 同步无障碍状态为 false
}
});
TIPS:自动高亮页js代码
// ========================
// 导航栏展开 / 收起(移动端汉堡按钮)
// ========================
// 选中“汉堡按钮”元素(类名为 .nav-toggle)
const btn = document.querySelector('.nav-toggle');
// 选中导航容器元素(id 为 site-nav)
const nav = document.getElementById('site-nav');
// 防御式判断:只有当页面上确实存在按钮时才绑定事件,避免空指针错误
if (btn) {
// 给按钮绑定“点击”事件
btn.addEventListener('click', () => {
// 切换导航容器的 .open 类名;返回布尔值:添加后为 true,移除后为 false
const isOpen = nav.classList.toggle('open');
// 同步无障碍状态:把按钮的 aria-expanded 设置为 "true" 或 "false"
// 让读屏器(辅助技术)能“听到”当前是展开还是收起
btn.setAttribute('aria-expanded', String(isOpen));
});
// 在整个文档上监听键盘按下事件
document.addEventListener('keydown', (e) => {
// 如果按下的是 Esc(Escape)键
if (e.key === 'Escape') {
// 强制移除 .open 类,关闭折叠菜单
nav.classList.remove('open');
// 同步无障碍状态为 "false"(已收起)
btn.setAttribute('aria-expanded', 'false');
}
});
}
// ========================
// 自动高亮当前页面链接(.active + aria-current)
// ========================
// 获取当前地址栏路径的最后一段文件名(如 "about.html")
// 若当前访问根路径(/),split 后的最后一段会是空字符串 ""
const currentPage = window.location.pathname.split('/').pop();
// 在导航容器中选中所有链接 <a> 元素
const navLinks = document.querySelectorAll('.nav a');
// 遍历每一个导航链接
navLinks.forEach(link => {
// 获取该链接的 href 属性(通常是相对路径文件名,如 "index.html")
const href = link.getAttribute('href');
// 判断是否与当前页面匹配:
// 1) 正常页面:href === currentPage
// 2) 首页特殊情况:当 currentPage 为空字符串(根路径),把 "index.html" 当作当前页
if (href === currentPage || (href === "index.html" && currentPage === "")) {
// 添加高亮样式类,用于视觉上的“当前页”标记
link.classList.add('active');
// 无障碍增强:告诉读屏器“这是当前页面对应的链接”
link.setAttribute('aria-current', 'page');
}
});
下列术语对应课程《Web前端技术》的知识/能力目标:HTML5 语义化、CSS3 布局(含 Flexbox/盒模型)、JavaScript DOM/事件、DevTools 调试与可访问性意识 等(与课程标准一致)。
<header>、<nav>、<ul>、<li>、<a> 等,组成“页眉+导航列表”。<a href="index.html"> 中 href 是属性;<nav id="site-nav"> 中 id 是属性。<nav>、页眉用 <header>,比用 <div> 更“自带含义”。aria-label="主导航"、aria-controls="site-nav"、aria-expanded="false" 让读屏器知道按钮控制谁、当前是否展开。<meta name="viewport">(视口)
指导移动端浏览器以设备宽度进行布局。
本例:保证媒体查询在手机上按预期生效。