跳到主要内容

语义化 HTML

语义化 HTML 是现代网页开发的核心概念,它使用正确的 HTML 元素来传达内容的含义和结构。

什么是语义化?

语义 vs 呈现

  • 语义(Semantics):元素所代表的意义
  • 呈现(Presentation):元素的外观样式

例如,<strong><b> 都可使文字加粗,但 <strong> 在语义上表示"重要",而 <b> 只是视觉上的加粗。

为什么需要语义化?

  1. 可访问性(Accessibility):屏幕阅读器能正确理解页面结构
  2. 搜索引擎优化(SEO):搜索引擎能更好地理解页面内容
  3. 代码可维护性:开发者更容易阅读和理解代码
  4. 跨设备兼容:不同设备能正确解析页面内容

语义化元素概览

文档结构元素

元素说明
<header>页面或区块的头部
<nav>导航区域
<main>主内容区域(唯一)
<article>独立完整的内容
<section>文档的章节
<aside>侧边栏内容
<footer>页面或区块的底部

文本语义元素

元素说明
<h1> - <h6>标题级别
<p>段落
<blockquote>块级引用
<q>行内引用
<abbr>缩写词
<time>日期/时间
<mark>标记/高亮
<address>联系信息

列表元素

元素说明
<ul>无序列表
<ol>有序列表
<dl>定义列表
<li>列表项

表格语义元素

元素说明
<table>表格容器
<thead>表头区域
<tbody>表体区域
<tfoot>表脚区域
<caption>表格标题

文档结构详解

header - 头部

<header> 用于表示页面或区块的头部区域:

<!-- 页面头部 -->
<header>
<h1>网站名称</h1>
<nav>
<a href="/">首页</a>
<a href="/about">关于我们</a>
</nav>
</header>

<!-- 文章头部 -->
<article>
<header>
<h2>文章标题</h2>
<p>发布时间:<time datetime="2024-01-01">2024年1月1日</time></p>
</header>
<!-- 文章内容 -->
</article>

<nav> 用于主要的导航链接区域:

<header>
<nav>
<ul>
<li><a href="/">首页</a></li>
<li><a href="/products">产品</a></li>
<li><a href="/about">关于我们</a></li>
</ul>
</nav>
</header>

<!-- 页面底部导航 -->
<footer>
<nav>
<a href="/terms">使用条款</a>
<a href="/privacy">隐私政策</a>
</nav>
</footer>
提示

不是所有链接都需要放在 <nav> 中,只有主要的导航链接组才需要使用这个元素。

main - 主内容

<main> 表示页面的主要 content(唯一使用):

<body>
<header>...</header>
<nav>...</nav>

<main>
<!-- 主要内容 -->
<article>
<h1>文章标题</h1>
<p>文章内容...</p>
</article>

<aside>
<!-- 侧边栏内容 -->
</aside>
</main>

<footer>...</footer>
</body>
注意

<main> 在页面中应该只出现一次,不要在 <article> 或其他区块内部使用。

article - 文章

<article> 表示独立、可分发的内容单元:

<!-- 博客文章 -->
<article>
<header>
<h2>如何学习编程</h2>
<p>作者:张三 | <time datetime="2024-01-15">2024年1月15日</time></p>
</header>

<p>内容正文...</p>

<footer>
<p>标签:<a href="/tag/programming">编程</a></p>
</footer>
</article>

<!-- 论坛帖子 -->
<article>
<h2>回复:如何学习编程</h2>
<p>李四的回复内容...</p>
</article>

<!-- 独立小部件 -->
<article>
<p>用户评论内容...</p>
</article>

section - 章节

<section> 用于将相关内容分组:

<article>
<header>
<h1>网页开发入门</h1>
</header>

<section>
<h2>第一章:HTML基础</h2>
<p>HTML的基本概念...</p>
</section>

<section>
<h2>第二章:CSS样式</h2>
<p>CSS的选择器...</p>
</section>

<section>
<h2>第三章:JavaScript</h2>
<p>JS的变量和数据类型...</p>
</section>
</article>
如何选择 article 和 section?
  • article:内容是独立、可分发的(如博客文章、新闻报道)
  • section:内容是主题相关的一组内容(如章节、标签页内容)

aside - 侧边栏

<aside> 表示与周围内容间接相关的区域:

<main>
<article>
<h1>学习HTML的重要性</h1>
<p>HTML是网页的基础...</p>
</article>

<aside>
<h3>相关推荐</h3>
<ul>
<li><a href="/css-guide">CSS入门指南</a></li>
<li><a href="/js-tutorial">JavaScript教程</a></li>
</ul>
</aside>
</main>

<footer> 用于表示页面或区块的底部:

<!-- 页面底部 -->
<footer>
<p>&copy; 2024 我的网站. All rights reserved.</p>
<address>
联系方式:<a href="mailto:[email protected]">[email protected]</a>
</address>
</footer>

<!-- 文章底部 -->
<article>
<footer>
<p>本文作者:张三</p>
<p>
标签:
<a href="/tag/html">HTML</a>
<a href="/tag/web">Web开发</a>
</p>
</footer>
</article>

文本语义元素

标题 h1-h6

<h1>页面主标题</h1>  <!-- 最重要的标题,每个页面一个 -->
<h2>章节标题</h2> <!-- 主要章节 -->
<h3>子章节标题</h3> <!-- 子章节 -->
<h4>小节标题</h4> <!-- 更小的节 -->
<h5>细节标题</h5> <!-- 很少使用 -->
<h6>最小标题</h6> <!-- 很少使用 -->
层级顺序

标题应该按层级顺序使用,不要跳级(如从 h1 直接跳到 h3)。搜索引擎会根据标题层级判断页面结构。

强调和重要性

<!-- 重要性,强调 -->
<p>请务必<strong>准时参加会议</strong></p>

<!-- 关键词 -->
<p>这是一段关于<strong>搜索引擎优化</strong>的文章。</p>

<!-- 语气强调 -->
<p>我真的<em>非常</em>抱歉!</p>

<!-- 技术术语 -->
<p>CSS 代表 <abbr title="Cascading Style Sheets">CSS</abbr></p>

效果预览:

请务必准时参加会议

我真的非常抱歉!

CSS 代表 CSS

引用

<!-- 块级引用 -->
<blockquote cite="https://example.com/source">
<p>这是引用的内容,通常会缩进显示。</p>
<footer><cite>引用来源</cite></footer>
</blockquote>

<!-- 行内引用 -->
<p>正如他所说:<q>学习是终身的任务</q></p>

> 这是一个块级引用的示例,内容通常会缩进显示。

时间和日期

<!-- 带机器可读格式的时间 -->
<p>会议时间:<time datetime="2024-01-15T14:30">2024年1月15日下午2:30</time></p>

<!-- 只包含日期 -->
<p>发布日期:<time datetime="2024-01-15">2024年1月15日</time></p>

<!-- 相对日期 -->
<p>更新时间:<time datetime="2024-01-15">三天前</time></p>

其他文本元素

<!-- 删除/插入内容 -->
<p>原价:<del>¥100</del>,现价:<ins>¥80</ins></p>

<!-- 高亮标记 -->
<p>重点内容:<mark>需要牢记的知识点</mark></p>

<!-- 代码 -->
<p>使用 <code>console.log()</code> 输出信息。</p>

<!-- 预格式化文本 -->
<pre><code>function hello() {
console.log("Hello!");
}</code></pre>

<!-- 缩写 -->
<p><abbr title="JavaScript">JS</abbr> 是流行的编程语言。</p>

<!-- 联系信息 -->
<address>
联系人:张三<br>
邮箱:<a href="mailto:[email protected]">[email protected]</a><br>
电话:138-0000-0000
</address>

效果预览:

  • ¥100 → ¥80(原价格删除线,新价格下划线)
  • 重点内容:需要牢记的知识点(高亮)
  • console.log():代码片段样式

列表语义

定义列表 dl/dt/dd

<dl>
<dt>HTML</dt>
<dd>超文本标记语言,用于创建网页结构。</dd>

<dt>CSS</dt>
<dd>层叠样式表,用于控制网页外观。</dd>

<dt>JavaScript</dt>
<dd>编程语言,为网页添加交互功能。</dd>
</dl>

在浏览器中渲染后,定义列表会显示为术语在前、定义在后的格式。

完整语义化页面示例

<!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>
</head>
<body>
<!-- 页面头部 -->
<header>
<h1>我的博客</h1>
<nav>
<ul>
<li><a href="/">首页</a></li>
<li><a href="/tutorials">教程</a></li>
<li><a href="/about">关于</a></li>
</ul>
</nav>
</header>

<!-- 主内容区 -->
<main>
<!-- 博客文章 -->
<article>
<header>
<h2>JavaScript 基础入门</h2>
<p>
作者:<span>张三</span> |
<time datetime="2024-01-15">2024年1月15日</time>
</p>
</header>

<section>
<h3>什么是JavaScript?</h3>
<p>JavaScript是一种<strong>脚本语言</strong>,用于...</p>
</section>

<section>
<h3>变量和数据类型</h3>
<p>在JavaScript中,我们可以使用<code>let</code><code>const</code>来声明变量...</p>

<h4>数据类型</h4>
<ul>
<li>Number(数字)</li>
<li>String(字符串)</li>
<li>Boolean(布尔)</li>
<li>Object(对象)</li>
</ul>
</section>

<section>
<h3>总结</h3>
<p>本文介绍了JavaScript的基础知识,包括...</p>
</section>

<footer>
<p>标签:
<a href="/tag/javascript">JavaScript</a>
<a href="/tag/programming">编程</a>
</p>
</footer>
</article>

<!-- 侧边栏 -->
<aside>
<section>
<h3>相关推荐</h3>
<ul>
<li><a href="/post/css-basics">CSS基础教程</a></li>
<li><a href="/post/html-intro">HTML入门</a></li>
</ul>
</section>

<section>
<h3>关于作者</h3>
<p>我是全栈开发者,热爱分享技术知识。</p>
</section>
</aside>
</main>

<!-- 页面底部 -->
<footer>
<p>&copy; 2024 我的博客. All rights reserved.</p>
<nav>
<a href="/privacy">隐私政策</a> |
<a href="/terms">使用条款</a>
</nav>
<address>
联系:<a href="mailto:[email protected]">[email protected]</a>
</address>
</footer>
</body>
</html>

非语义元素

div 和 span

当没有合适的语义元素时,使用通用的无语义元素:

<!-- div:块级无语义容器 -->
<div class="card">
<div class="card-header">标题</div>
<div class="card-body">内容</div>
</div>

<!-- span:行内无语义容器 -->
<p>价格:<span class="price">¥99</span></p>
<p>状态:<span class="badge">热卖中</span></p>
何时使用 div?
  • 纯用于样式的容器
  • 需要用 JavaScript 操作的一组元素
  • 实在没有合适的语义元素

交互式语义元素

HTML 提供了一些内置的交互式元素,无需 JavaScript 即可实现基本的交互功能。

details 和 summary 折叠内容

<details> 元素创建一个可折叠的内容区域,用户可以点击展开或收起。

<details>
<summary>点击查看更多信息</summary>
<p>这里是隐藏的详细内容,只有当用户点击 summary 后才会显示。</p>
<p>可以包含任意 HTML 内容。</p>
</details>

常用属性:

属性说明
open布尔属性,设置后默认展开状态
<!-- 默认展开 -->
<details open>
<summary>常见问题</summary>
<p>这里是问题的答案...</p>
</details>

实际应用场景:

<!-- FAQ 页面 -->
<details>
<summary>如何重置密码?</summary>
<p>点击登录页面的"忘记密码"链接,输入注册邮箱后按照提示操作即可。</p>
</details>

<details>
<summary>支持哪些支付方式?</summary>
<p>我们支持支付宝、微信支付、银行卡等多种支付方式。</p>
</details>

<!-- 代码展示 -->
<details>
<summary>查看源代码</summary>
<pre><code>function hello() {
console.log("Hello, World!");
}</code></pre>
</details>

<!-- 嵌套使用 -->
<details>
<summary>第一级内容</summary>
<p>第一级的详细内容...</p>
<details>
<summary>第二级内容</summary>
<p>第二级的详细内容...</p>
</details>
</details>

自定义样式:

/* 自定义展开图标 */
details summary {
cursor: pointer;
list-style: none;
}

details summary::-webkit-details-marker {
display: none;
}

/* 使用自定义图标 */
details summary::before {
content: "▶ ";
}

details[open] summary::before {
content: "▼ ";
}

/* 添加动画效果 */
details {
transition: all 0.3s ease;
}

details summary:focus {
outline: 2px solid #3498db;
outline-offset: 2px;
}

dialog 对话框

<dialog> 元素用于创建模态或非模态对话框。

<dialog id="myDialog">
<h2>对话框标题</h2>
<p>这是对话框的内容。</p>
<button id="closeBtn">关闭</button>
</dialog>

<button id="openBtn">打开对话框</button>

<script>
const dialog = document.getElementById('myDialog');
const openBtn = document.getElementById('openBtn');
const closeBtn = document.getElementById('closeBtn');

openBtn.addEventListener('click', () => {
dialog.showModal(); // 模态方式打开
// dialog.show(); // 非模态方式打开
});

closeBtn.addEventListener('click', () => {
dialog.close();
});
</script>

打开方式:

方法说明
show()非模态方式打开,用户可以与页面其他元素交互
showModal()模态方式打开,用户只能与对话框交互,背景变暗

对话框样式:

/* 对话框基础样式 */
dialog {
padding: 20px;
border: none;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
max-width: 500px;
}

/* 模态背景遮罩 */
dialog::backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(2px);
}

/* 打开动画 */
dialog {
opacity: 0;
transform: scale(0.9);
transition: opacity 0.3s, transform 0.3s;
}

dialog[open] {
opacity: 1;
transform: scale(1);
}

完整对话框示例:

<!-- 确认对话框 -->
<dialog id="confirmDialog">
<form method="dialog">
<h3>确认删除</h3>
<p>确定要删除这个项目吗?此操作无法撤销。</p>
<div class="dialog-actions">
<button value="cancel" formmethod="dialog">取消</button>
<button value="confirm" autofocus>确认删除</button>
</div>
</form>
</dialog>

<script>
const dialog = document.getElementById('confirmDialog');

function confirmDelete() {
dialog.showModal();

dialog.addEventListener('close', () => {
if (dialog.returnValue === 'confirm') {
// 用户点击确认
console.log('已确认删除');
} else {
// 用户取消
console.log('已取消');
}
});
}
</script>

<search> 元素是 HTML 中的新语义元素,用于标识搜索或过滤功能的区域。

<search>
<form action="/search" method="GET">
<input type="search" name="q" placeholder="搜索...">
<button type="submit">搜索</button>
</form>
</search>

<!-- 带过滤功能 -->
<search>
<label for="filter">筛选:</label>
<select id="filter" name="category">
<option value="">全部分类</option>
<option value="tech">技术</option>
<option value="design">设计</option>
</select>
<input type="search" placeholder="关键词...">
</search>

<search> 元素帮助辅助技术识别页面中的搜索功能区域,提升可访问性。

Popover API 弹出框

Popover API 是 HTML 原生的弹出框机制,无需 JavaScript 即可创建常见的弹出 UI,如菜单、提示框、通知等。它与 <dialog> 元素互补:Popover 用于非模态弹出框,<dialog> 用于模态对话框。

Popover 的三种状态

Popover 通过 popover 属性创建,该属性支持三种值:

说明
auto默认值,自动状态。支持"轻量关闭"(点击外部关闭),同时只能显示一个 auto popover
manual手动状态。不支持轻量关闭,多个 manual popover 可以同时显示
hint提示状态。不会关闭 auto popover,适合工具提示等场景

声明式创建 Popover

最简单的方式是使用 HTML 属性声明式创建:

<!-- popover 元素 -->
<div id="menu" popover>
<ul>
<li><a href="#">选项一</a></li>
<li><a href="#">选项二</a></li>
<li><a href="#">选项三</a></li>
</ul>
</div>

<!-- 控制按钮 -->
<button popovertarget="menu">打开菜单</button>

popovertarget 属性值为目标 popover 元素的 id,点击按钮即可切换 popover 的显示状态。

popovertargetaction 属性

默认情况下,按钮会切换 popover 的显示/隐藏状态。使用 popovertargetaction 可以指定具体行为:

说明
toggle切换显示/隐藏(默认)
show只显示
hide只隐藏
<!-- 分别控制显示和隐藏 -->
<button popovertarget="menu" popovertargetaction="show">显示菜单</button>
<button popovertarget="menu" popovertargetaction="hide">隐藏菜单</button>

auto 状态的轻量关闭

popover="auto"(或省略值)的弹出框支持"轻量关闭":

  • 点击弹出框外部区域自动关闭
  • Esc 键关闭
  • 打开新的 auto popover 时,之前打开的会自动关闭
<div id="tooltip" popover="auto">
这是一个提示框,点击外部会自动关闭。
</div>
<button popovertarget="tooltip">显示提示</button>

manual 状态:多弹出框并存

当需要同时显示多个弹出框时,使用 popover="manual"

<div id="notification1" popover="manual">
通知一:新消息到达
</div>
<div id="notification2" popover="manual">
通知二:系统更新可用
</div>

<button popovertarget="notification1">显示通知1</button>
<button popovertarget="notification2">显示通知2</button>

<!-- 两个通知可以同时显示 -->

hint 状态:工具提示

popover="hint" 用于工具提示等场景,它不会关闭已打开的 auto popover:

<!-- 主菜单 -->
<div id="mainMenu" popover="auto">
<button>文件</button>
<button>编辑</button>
<button>视图</button>
</div>

<!-- 工具提示(不会关闭主菜单) -->
<div id="tooltip" popover="hint">
点击打开主菜单
</div>

<button
popovertarget="mainMenu"
onmouseenter="document.getElementById('tooltip').showPopover()"
onmouseleave="document.getElementById('tooltip').hidePopover()">
菜单
</button>

JavaScript API

除了声明式方式,也可以通过 JavaScript 控制 popover:

<div id="myPopover" popover>
弹出框内容
</div>
<button id="toggleBtn">切换</button>

<script>
const popover = document.getElementById('myPopover');
const btn = document.getElementById('toggleBtn');

// 显示 popover
popover.showPopover();

// 隐藏 popover
popover.hidePopover();

// 切换显示状态
btn.addEventListener('click', () => {
popover.togglePopover();
});

// 检查是否支持
if (HTMLElement.prototype.showPopover) {
console.log('浏览器支持 Popover API');
}
</script>

Popover 事件

Popover 提供两个事件用于响应状态变化:

事件说明
beforetogglepopover 显示或隐藏之前触发
togglepopover 显示或隐藏之后触发

事件对象的 oldStatenewState 属性表示状态变化:

<div id="myPopover" popover>
弹出框内容
</div>

<script>
const popover = document.getElementById('myPopover');

popover.addEventListener('beforetoggle', (event) => {
console.log(`即将从 ${event.oldState} 变为 ${event.newState}`);
// oldState: "closed" 或 "open"
// newState: "open" 或 "closed"
});

popover.addEventListener('toggle', (event) => {
if (event.newState === 'open') {
console.log('弹出框已打开');
} else {
console.log('弹出框已关闭');
}
});
</script>

CSS 样式

:popover-open 伪类

:popover-open 伪类匹配当前显示中的 popover:

/* 弹出框基础样式 */
[popover] {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

/* 仅当显示时的样式 */
[popover]:popover-open {
animation: fadeIn 0.2s ease;
}

@keyframes fadeIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}

::backdrop 伪元素

::backdrop 伪元素可以设置 popover 背后的遮罩层样式:

#myPopover::backdrop {
background: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(4px);
}

Popover 动画

由于 popover 隐藏时是 display: none,需要使用 @starting-style 规则和 transition-behavior 来实现动画:

[popover] {
/* 基础样式 */
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);

/* 过渡设置 */
transition:
opacity 0.3s,
transform 0.3s,
display 0.3s allow-discrete,
overlay 0.3s allow-discrete;

/* 隐藏状态 */
opacity: 0;
transform: scale(0.9);
}

/* 显示状态 */
[popover]:popover-open {
opacity: 1;
transform: scale(1);
}

/* 进入动画起始样式 */
@starting-style {
[popover]:popover-open {
opacity: 0;
transform: scale(0.9);
}
}

/* 背景遮罩动画 */
[popover]::backdrop {
background: rgba(0, 0, 0, 0);
transition: background 0.3s;
}

[popover]:popover-open::backdrop {
background: rgba(0, 0, 0, 0.5);
}

Popover 与锚点定位

Popover 可以配合 CSS 锚点定位,将弹出框定位在触发按钮附近:

<style>
.menu-trigger {
anchor-name: --menu-anchor;
}

#dropdown-menu {
position: fixed;
position-anchor: --menu-anchor;
position-area: bottom span-all;
margin-top: 4px;
}
</style>

<button class="menu-trigger" popovertarget="dropdown-menu">下拉菜单</button>
<div id="dropdown-menu" popover>
<ul>
<li>选项一</li>
<li>选项二</li>
<li>选项三</li>
</ul>
</div>

popovertarget 建立关联时,浏览器会自动创建隐式的锚点引用,无需手动设置 anchor-nameposition-anchor

嵌套 Popover

Popover 支持嵌套,子 popover 可以在父 popover 内部显示:

<div id="parentMenu" popover="auto">
<button popovertarget="subMenu">更多选项</button>

<div id="subMenu" popover="auto">
<button>子选项一</button>
<button>子选项二</button>
</div>
</div>

<button popovertarget="parentMenu">打开菜单</button>

Popover vs Dialog 选择指南

特性PopoverDialog
模态性始终非模态可模态可非模态
轻量关闭auto 状态支持不支持
层级自动提升到顶层自动提升到顶层
无障碍角色无默认角色默认 role="dialog"
焦点管理不捕获焦点模态时捕获焦点
典型用途菜单、工具提示、通知确认框、表单弹窗

使用建议:

  • 需要用户必须处理的内容 → 使用 <dialog>
  • 非侵入式的信息展示或操作 → 使用 Popover

无障碍特性

Popover API 自动处理多项无障碍特性:

  1. 焦点管理:打开 popover 时,焦点顺序会包含 popover 内的可聚焦元素
  2. ARIA 关联:自动在触发器和 popover 之间建立 aria-expandedaria-details 关系
  3. 键盘支持Esc 键可以关闭 auto 状态的 popover

完整示例:下拉菜单

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Popover 下拉菜单示例</title>
<style>
.dropdown-trigger {
padding: 10px 20px;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}

.dropdown-trigger:hover {
background: #2980b9;
}

#dropdown-menu {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 8px 0;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
min-width: 180px;

transition:
opacity 0.2s,
transform 0.2s,
display 0.2s allow-discrete;
opacity: 0;
transform: translateY(-8px);
}

#dropdown-menu:popover-open {
opacity: 1;
transform: translateY(0);
}

@starting-style {
#dropdown-menu:popover-open {
opacity: 0;
transform: translateY(-8px);
}
}

#dropdown-menu ul {
list-style: none;
margin: 0;
padding: 0;
}

#dropdown-menu li a {
display: block;
padding: 10px 16px;
color: #333;
text-decoration: none;
}

#dropdown-menu li a:hover {
background: #f5f5f5;
}

#dropdown-menu li a:focus {
background: #e8f4fc;
outline: none;
}

#dropdown-menu::backdrop {
background: transparent;
}
</style>
</head>
<body>
<h1>Popover 下拉菜单示例</h1>

<button class="dropdown-trigger" popovertarget="dropdown-menu">
更多操作 ▾
</button>

<div id="dropdown-menu" popover>
<ul>
<li><a href="#">新建文件</a></li>
<li><a href="#">打开文件</a></li>
<li><a href="#">保存</a></li>
<li><a href="#">另存为...</a></li>
<li><hr style="border: none; border-top: 1px solid #eee; margin: 4px 0;"></li>
<li><a href="#">退出</a></li>
</ul>
</div>
</body>
</html>

可访问性注意事项

使用正确的标题层级

<!-- 正确 -->
<h1>页面标题</h1>
<h2>主要章节</h2>
<h3>子章节</h3>

<!-- 错误:跳级 -->
<h1>页面标题</h1>
<h3>直接跳到h3</h3>

链接文本

<!-- 好的链接文本 -->
<a href="/article">阅读更多关于HTML的文章</a>
<a href="/products">查看所有产品 →</a>

<!-- 不好的链接文本(屏幕阅读器无法理解) -->
<a href="#">点击这里</a>
<a href="#">更多</a>
<a href="javascript:void(0)">链接</a>

列表结构

屏幕阅读器会告诉用户列表中有多少项目:

<!-- 使用正确的列表元素 -->
<ul>
<li>项目一</li>
<li>项目二</li>
</ul>

小结

本章学习了:

  1. 语义化的重要性:可访问性、SEO、可维护性
  2. 文档结构元素:header、nav、main、article、section、aside、footer
  3. 文本语义元素:h1-h6、strong、em、blockquote、time 等
  4. 交互式语义元素:details/summary、dialog、search
  5. Popover API:三种状态(auto/manual/hint)、声明式创建、JavaScript API、CSS样式和动画
  6. 何时使用无语义元素:div 和 span
  7. 可访问性注意事项:标题层级、链接文本、列表结构

练习

  1. 将一个使用 div 堆砌的页面改写为语义化结构
  2. 创建一个博客页面,包含完整的语义化结构
  3. 为所有表单元素添加正确的 label
  4. 使用 <details> 创建一个 FAQ 折叠列表
  5. 创建一个确认删除的 <dialog> 对话框
  6. 使用 Popover API 创建一个下拉菜单
  7. 实现一个带动画效果的 popover
  8. 检查自己的代码,确保标题层级不跳级
  9. 使用语义化元素重写一段包含引用的内容