第一篇:HTML5 核心知识全解 + 项目起步

本系列共 6 篇,从零到一构建完整前端知识体系:

① HTML5 全部知识点 + 项目搭建 → ② CSS3 全部知识点 → ③ JavaScript 基础语法 → ④ JavaScript 进阶(DOM/BOM/事件)→ ⑤ ES6+ 与现代工程化 → ⑥ 综合项目实战(TodoList + 数据可视化)


目录

  1. [HTML5 是什么](#HTML5 是什么)
  2. [文档骨架:DOCTYPE 与 head](#文档骨架:DOCTYPE 与 head)
  3. [语义化标签(HTML5 核心)](#语义化标签(HTML5 核心))
  4. 文本内容标签全解
  5. 列表与表格
  6. 超链接与图片
  7. [表单:HTML5 最重要的交互入口](#表单:HTML5 最重要的交互入口)
  8. [多媒体:audio / video / source](#多媒体:audio / video / source)
  9. [全局属性与 data-* 自定义数据](#全局属性与 data-* 自定义数据)
  10. [HTML5 新 API 概览](#HTML5 新 API 概览)
  11. 可访问性(a11y)
  12. 项目搭建实战:个人任务管理器骨架
  13. 本篇小结与练习

一、HTML5 是什么

HTML(HyperText Markup Language,超文本标记语言) 是网页的"骨架",它负责描述内容的结构与语义,而不是外观(外观交给 CSS),也不是行为(行为交给 JavaScript)。

三者分工:

技术 职责 类比
HTML 结构 / 语义 人的骨骼
CSS 表现 / 样式 人的皮肤衣着
JavaScript 行为 / 交互 人的肌肉神经

HTML5 是 HTML 的第五个大版本(2014 年正式定稿),相比 HTML4 带来的重大变化:

  • 新增语义化标签 :header、nav、main、article、section、aside、footer、figure 等
  • 新增表单控件类型 :email、date、range、color 等,以及原生校验
  • 新增多媒体标签 :audio、video,摆脱 Flash
  • 新增图形能力 :canvas、svg
  • 新增存储与离线 :localStorage、sessionStorage、IndexedDB、Application Cache
  • 新增一系列 JS API:地理定位、拖放、Web Worker、WebSocket、File API 等

重要观念 :HTML5 不是"一个标签语言",而是 HTML + CSS3 + JavaScript API 的统称技术集合。


二、文档骨架:DOCTYPE 与 head

一个标准 HTML5 文档的最小结构:

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="这是一个 HTML5 学习示例页面">
  <meta name="keywords" content="HTML5,前端,教程">
  <meta name="author" content="Your Name">
  <title>HTML5 教程 - 第一篇</title>
  <link rel="icon" href="./favicon.ico" type="image/x-icon">
  <link rel="stylesheet" href="./css/style.css">
</head>
<body>
  <!-- 页面内容 -->
  <script src="./js/main.js" defer></script>
</body>
</html>

逐行拆解

1. <!DOCTYPE html>

文档类型声明,必须是文件第一行。它告诉浏览器用标准模式渲染。HTML5 的 doctype 极简,不再需要写一长串 DTD。

2. <html lang="zh-CN">

根元素。lang 属性非常重要:

  • 影响屏幕阅读器的发音
  • 影响浏览器自动翻译判断
  • 影响 CSS 的 :lang() 选择器与字体回退

常用值:zh-CN(简体中文)、en(英语)、ja(日语)。

3. <head> 中的 meta 标签

meta 作用
charset="UTF-8" 字符编码,必须放在 head 最前面,否则中文乱码
viewport 移动端视口设置,响应式必备
description SEO 描述,搜索引擎结果摘要
keywords 关键词(现代 SEO 权重已很低)
author 作者
theme-color 移动端浏览器地址栏颜色
http-equiv="refresh" 定时刷新/跳转(不推荐)

viewport 详细参数:

html 复制代码
<!-- 标准写法:宽度等于设备宽度,初始缩放 1 倍 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- 禁止用户缩放(谨慎使用,影响可访问性) -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

4. <script> 的加载时机

html 复制代码
<!-- 1. 普通:遇到即下载并执行,阻塞 HTML 解析 ❌ -->
<script src="a.js"></script>

<!-- 2. async:异步下载,下载完立即执行,执行顺序不确定 -->
<script src="a.js" async></script>

<!-- 3. defer:异步下载,等 HTML 解析完再按顺序执行 ✅ 推荐 -->
<script src="a.js" defer></script>
方式 下载 执行时机 顺序
默认 同步阻塞 立即 有序
async 并行 下载完立即 无序
defer 并行 DOMContentLoaded 之前 有序

三、语义化标签(HTML5 核心)

这是 HTML5 最重要的思想:用正确的标签做正确的事 ,而不是满屏 <div>。

3.1 页面结构标签

html 复制代码
<body>
  <header>          <!-- 页头:logo、标题、导航 -->
    <h1>我的网站</h1>
    <nav>           <!-- 导航区 -->
      <ul>
        <li><a href="#home">首页</a></li>
        <li><a href="#about">关于</a></li>
      </ul>
    </nav>
  </header>

  <main>            <!-- 页面主内容,一个页面只应有一个 -->
    <article>       <!-- 独立完整的内容单元,如一篇博客 -->
      <h2>文章标题</h2>
      <p>正文......</p>

      <section>     <!-- 文章内的分节,通常带标题 -->
        <h3>小节标题</h3>
        <p>小节内容</p>
      </section>

      <figure>      <!-- 图文组合 -->
        <img src="chart.png" alt="销售趋势图">
        <figcaption>图 1:2024 年销售趋势</figcaption>
      </figure>
    </article>

    <aside>         <!-- 侧边栏:相关内容、广告、推荐 -->
      <h3>相关阅读</h3>
      <ul><li><a href="#">文章 A</a></li></ul>
    </aside>
  </main>

  <footer>          <!-- 页脚:版权、备案、联系方式 -->
    <p>&copy; 2025 我的网站</p>
  </footer>
</body>

3.2 各标签语义对比表

标签 语义 使用场景 能否嵌套
header 头部 页面/文章/区块的头部 可多处
nav 导航 主要链接组 可多处
main 主体 页面唯一核心内容 只能一个
article 独立文章 博客、新闻、评论、卡片 可嵌套
section 章节 有主题的内容分组 可嵌套
aside 侧边 补充内容 可多处
footer 页脚 版权、相关链接 可多处
figure 图文块 图 + 说明 可嵌套
figcaption 图说明 figure 的标题 只能放 figure 内
details 折叠详情 问答、折叠面板 可嵌套
summary 折叠标题 details 的可见标题 只能放 details 内
mark 高亮 搜索结果高亮 行内
time 时间 日期时间,配 datetime 行内
address 联系信息 作者联系方式 块级

3.3 details / summary 原生折叠

html 复制代码
<details open>
  <summary>什么是语义化?</summary>
  <p>用合适的标签表达内容含义,让机器和人都能理解。</p>
</details>

open 属性表示默认展开。这是零 JavaScript 实现的折叠面板。

3.4 <time> 与机器可读时间

html 复制代码
<p>发布于 <time datetime="2025-01-15T09:30">2025 年 1 月 15 日 上午 9:30</time></p>

datetime 让搜索引擎和浏览器能解析出精确时间。

3.5 div 与 span 何时用?

  • div:无语义的块级容器,纯为布局/样式服务时使用
  • span:无语义的行内容器,为局部文字加样式时使用

原则:能用语义标签就不用 div,但也不必为了语义而强行套壳。


四、文本内容标签全解

4.1 标题 h1 ~ h6

html 复制代码
<h1>一级标题(页面主标题,建议只有一个)</h1>
<h2>二级标题</h2>
<h3>三级标题</h3>
<h4>四级标题</h4>
<h5>五级标题</h5>
<h6>六级标题</h6>

规则:

  • 不要跳级(h1 后直接 h3 ❌)
  • 不要用标题标签来"让字变大"(那是 CSS 的活)
  • 标题层级构成页面的大纲(outline)

4.2 段落与换行

html 复制代码
<p>这是一个段落。段落之间会自动有间距。</p>
<p>第一行<br>第二行(br 是强制换行,不产生新段落)</p>
<hr>  <!-- 主题分隔线,语义上的分断 -->

br 只用于同一段落内的换行(如诗歌、地址),不要用它来做段落间距。

4.3 行内语义标签

html 复制代码
<strong>重要内容</strong>        <!-- 语义:重要 → 默认加粗 -->
<b>关键词</b>                    <!-- 无语义,仅样式加粗 -->
<em>强调</em>                    <!-- 语义:强调 → 默认斜体 -->
<i>外来词/术语</i>               <!-- 无语义,仅样式斜体 -->
<mark>高亮文本</mark>            <!-- 标记,默认黄底 -->
<small>附属细则</small>          <!-- 小字,如版权声明 -->
<del>已删除</del>                <!-- 删除线,如原价 -->
<ins>新插入</ins>                <!-- 下划线,如现价 -->
<sub>下标</sub> H<sub>2</sub>O
<sup>上标</sup> x<sup>2</sup>
<code>console.log()</code>       <!-- 代码片段,等宽字体 -->
<kbd>Ctrl + C</kbd>              <!-- 键盘输入 -->
<samp>输出结果</samp>            <!-- 程序输出 -->
<var>变量名</var>                <!-- 变量 -->
<abbr title="HyperText Markup Language">HTML</abbr>  <!-- 缩写 -->
<cite>《JavaScript 高级程序设计》</cite>              <!-- 作品名 -->
<q>行内引用</q>                  <!-- 短引用,自动加引号 -->
<blockquote cite="https://example.com">
  块级引用,通常缩进显示。
</blockquote>
<pre>预格式化文本
  空格   和
    换行都会被保留</pre>

<code> + <pre> 组合是展示代码的标准方式:

html 复制代码
<pre><code>
function greet(name) {
  return `Hello, ${name}`;
}
</code></pre>

4.4 实体字符(Escape)

实体 显示 说明
&lt; < 小于号
&gt; > 大于号
&amp; & 和号
&quot; " 双引号
' ' 单引号
&nbsp; (空格) 不换行空格
&copy; © 版权
&reg; ® 注册商标
&trade; ™ 商标
&times; × 乘号
&divide; ÷ 除号
&hearts; ♥ 心形
&rarr; → 右箭头

想显示 <div> 这样的标签文本,必须写成 &lt;div&gt;。


五、列表与表格

5.1 三种列表

html 复制代码
<!-- 1. 无序列表 unordered list -->
<ul>
  <li>苹果</li>
  <li>香蕉</li>
</ul>

<!-- 2. 有序列表 ordered list -->
<ol start="3" reversed type="A">
  <li>第三步</li>
  <li>第二步</li>
  <li>第一步</li>
</ol>

<!-- 3. 描述列表 description list -->
<dl>
  <dt>HTML</dt>              <!-- 术语 -->
  <dd>超文本标记语言</dd>     <!-- 描述 -->
  <dt>CSS</dt>
  <dd>层叠样式表</dd>
</dl>

<ol> 的属性:

  • type="1|A|a|I|i" 编号类型
  • start="3" 起始值
  • reversed 倒序

列表嵌套(导航菜单常用):

html 复制代码
<ul>
  <li>前端
    <ul>
      <li>HTML</li>
      <li>CSS</li>
    </ul>
  </li>
  <li>后端</li>
</ul>

⚠️ <ul> / <ol> 的直接子元素只能是 <li> ,不能塞 <div>。

5.2 表格

html 复制代码
<table>
  <caption>2024 年季度销售表</caption>

  <colgroup>
    <col style="width: 120px">
    <col span="2">
  </colgroup>

  <thead>
    <tr>
      <th scope="col">季度</th>
      <th scope="col">销售额</th>
      <th scope="col">同比</th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <th scope="row">Q1</th>
      <td>120 万</td>
      <td>+8%</td>
    </tr>
    <tr>
      <th scope="row">Q2</th>
      <td>150 万</td>
      <td>+12%</td>
    </tr>
  </tbody>

  <tfoot>
    <tr>
      <td colspan="1">合计</td>
      <td colspan="2">270 万</td>
    </tr>
  </tfoot>
</table>

关键属性:

  • colspan="2":横向合并 2 列
  • rowspan="2":纵向合并 2 行
  • scope="col|row":声明表头作用范围,无障碍必写
  • caption:表格标题,必须紧跟 <table> 开始标签

HTML5 已废弃的表格属性 (不要用):border、cellpadding、cellspacing、width、align、bgcolor → 全部用 CSS 代替。


六、超链接与图片

6.1 <a> 超链接

html 复制代码
<!-- 外部链接 -->
<a href="https://developer.mozilla.org" target="_blank" rel="noopener noreferrer">
  MDN 文档
</a>

<!-- 站内链接 -->
<a href="./about.html">关于我们</a>
<a href="/products/list.html">产品列表</a>

<!-- 锚点跳转(页面内) -->
<a href="#section-2">跳到第二节</a>
<h2 id="section-2">第二节</h2>

<!-- 邮件 / 电话 -->
<a href="mailto:hi@example.com?subject=咨询&body=你好">发邮件</a>
<a href="tel:+8613800000000">拨打电话</a>

<!-- 下载 -->
<a href="./files/report.pdf" download="年度报告.pdf">下载报告</a>

target 取值:

值 含义
_self 当前窗口(默认)
_blank 新标签页
_parent 父框架
_top 顶层窗口

安全提示 :target="_blank" 必须加 rel="noopener noreferrer",防止新页面通过 window.opener 操控原页面(钓鱼攻击)。

6.2 <img> 图片

html 复制代码
<img
  src="./images/avatar.webp"
  alt="用户头像:一位戴眼镜的男性"
  width="200"
  height="200"
  loading="lazy"
  decoding="async"
>

alt 属性是必须的,三种场景:

  1. 图片承载信息:写清图片内容(如"2024 年销售额增长 12% 的柱状图")
  2. 装饰性图片 :写 alt=""(空字符串),让屏幕阅读器跳过
  3. 图片是链接:写清链接目标(如"返回首页")

性能属性:

  • loading="lazy" 懒加载,进入视口附近才下载
  • decoding="async" 异步解码
  • width / height 提前占位,防止 CLS(布局抖动)

6.3 响应式图片 srcset / sizes

html 复制代码
<img
  src="./img/photo-800.jpg"
  srcset="./img/photo-400.jpg 400w,
          ./img/photo-800.jpg 800w,
          ./img/photo-1600.jpg 1600w"
  sizes="(max-width: 600px) 100vw,
         (max-width: 1200px) 50vw,
         800px"
  alt="示例照片"
>
  • srcset 提供多个分辨率候选
  • sizes 告诉浏览器不同视口下图片的显示宽度
  • 浏览器自动选择最合适的那个下载

6.4 <picture> 艺术方向 / 格式回退

html 复制代码
<picture>
  <!-- 支持 AVIF 就用它 -->
  <source srcset="./img/hero.avif" type="image/avif">
  <!-- 支持 WebP 就用它 -->
  <source srcset="./img/hero.webp" type="image/webp">
  <!-- 竖屏时裁切成竖图 -->
  <source media="(orientation: portrait)" srcset="./img/hero-portrait.jpg">
  <!-- 兜底 -->
  <img src="./img/hero.jpg" alt="产品主图">
</picture>

6.5 <figure> 图文组合

html 复制代码
<figure>
  <img src="./img/chart.png" alt="月度活跃用户趋势图">
  <figcaption>图 2:2024 年月活用户增长情况</figcaption>
</figure>

七、表单:HTML5 最重要的交互入口

7.1 表单容器

html 复制代码
<form action="/api/submit" method="post" enctype="multipart/form-data" novalidate>
  ...
</form>
属性 说明
action 提交地址
method get(参数拼 URL) / post(请求体)
enctype application/x-www-form-urlencoded(默认)/ multipart/form-data(含文件上传必用 )/ text/plain
novalidate 关闭浏览器原生校验
autocomplete on / off
target 提交后在哪打开响应

7.2 <label> 与表单控件的绑定

两种绑定方式:

html 复制代码
<!-- 方式 1:for + id(推荐) -->
<label for="username">用户名</label>
<input type="text" id="username" name="username">

<!-- 方式 2:包裹 -->
<label>
  密码
  <input type="password" name="password">
</label>

绑定后,点击 label 文字即可聚焦输入框;屏幕阅读器也能正确朗读。表单必写 label。

7.3 <input> 的全部 type(HTML5 重点)

html 复制代码
<!-- ===== 基础类型 ===== -->
<input type="text"     name="nickname" placeholder="请输入昵称" maxlength="20">
<input type="password" name="pwd" placeholder="密码">
<input type="hidden"   name="token" value="abc123">

<!-- ===== HTML5 新增类型 ===== -->
<input type="email"    name="email" placeholder="you@example.com" multiple>
<input type="tel"      name="phone" placeholder="13800000000" pattern="1[3-9]\d{9}">
<input type="url"      name="site"  placeholder="https://example.com">
<input type="number"   name="age"   min="1" max="120" step="1" value="18">
<input type="range"    name="volume" min="0" max="100" step="5" value="50">
<input type="date"     name="birthday">
<input type="time"     name="meeting">
<input type="datetime-local" name="appointment">
<input type="month"    name="month">
<input type="week"     name="week">
<input type="color"    name="theme" value="#3b82f6">
<input type="search"   name="q" placeholder="搜索...">

<!-- ===== 选择类 ===== -->
<input type="checkbox" id="agree" name="agree" value="yes" checked>
<label for="agree">我已阅读并同意协议</label>

<input type="radio" id="male" name="gender" value="male" checked>
<label for="male">男</label>
<input type="radio" id="female" name="gender" value="female">
<label for="female">女</label>

<!-- ===== 文件 ===== -->
<input type="file" name="avatar" accept="image/png, image/jpeg" multiple>

<!-- ===== 按钮类 ===== -->
<input type="submit" value="提交">
<input type="reset"  value="重置">
<input type="button" value="普通按钮">

注意 :radio 必须同 name 才能互斥;checkbox 需要 value 才能提交有效值。

7.4 其他表单控件

html 复制代码
<!-- 多行文本 -->
<textarea name="intro" rows="5" cols="40" placeholder="介绍一下自己" maxlength="200"></textarea>

<!-- 下拉选择 -->
<select name="city" multiple size="3">
  <optgroup label="华北">
    <option value="bj" selected>北京</option>
    <option value="tj">天津</option>
  </optgroup>
  <optgroup label="华东">
    <option value="sh">上海</option>
    <option value="hz">杭州</option>
  </optgroup>
</select>

<!-- 数据列表:输入框 + 候选建议 -->
<input list="browsers" name="browser">
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
</datalist>

<!-- 进度条 -->
<progress value="70" max="100">70%</progress>

<!-- 度量衡(如磁盘用量) -->
<meter value="0.7" min="0" max="1" low="0.3" high="0.8" optimum="0.2">70%</meter>

<!-- 按钮 -->
<button type="submit">提交</button>
<button type="reset">重置</button>
<button type="button" onclick="alert('hi')">点我</button>

<!-- 分组与说明 -->
<fieldset>
  <legend>收货信息</legend>
  <label>收件人 <input type="text" name="receiver"></label>
</fieldset>

⚠️ <button> 在表单内默认 type="submit" ,若不希望提交必须显式写 type="button",这是新手最常见的坑之一。

7.5 原生表单校验属性

html 复制代码
<input type="text" name="user" required minlength="3" maxlength="10"
       pattern="[A-Za-z0-9_]+" title="只能包含字母、数字和下划线">

<input type="email" name="email" required>

<input type="number" name="score" min="0" max="100" step="0.5">

<input type="password" name="pwd" required minlength="8">
属性 作用
required 必填
minlength / maxlength 字符长度
min / max / step 数值范围与步长
pattern 正则(隐式整体匹配 ,不用写 ^$)
title 校验失败时的提示语
autofocus 自动聚焦
readonly 只读(可提交)
disabled 禁用(不提交)
autocomplete 自动填充
inputmode 移动端键盘类型,如 numeric

用 JS 控制校验:

javascript 复制代码
const input = document.querySelector('#username');

console.log(input.validity.valid);      // 是否通过校验
console.log(input.validity.valueMissing); // 是否因 required 失败
console.log(input.validationMessage);   // 浏览器给的提示文字

input.setCustomValidity('用户名已被占用');  // 自定义错误
input.setCustomValidity('');               // 清除自定义错误

7.6 表单提交行为

html 复制代码
<!-- GET:参数拼在 URL 后,?a=1&b=2,不安全、有长度限制,适合搜索 -->
<form action="/search" method="get">...</form>

<!-- POST:参数在请求体,适合提交数据 -->
<form action="/api/user" method="post">...</form>

用 JS 阻止默认提交并自行处理(最常用):

javascript 复制代码
const form = document.querySelector('#myForm');

form.addEventListener('submit', (e) => {
  e.preventDefault();                    // 阻止浏览器默认提交
  const data = new FormData(form);       // 收集所有带 name 的字段
  console.log(Object.fromEntries(data));
  // fetch('/api', { method: 'POST', body: data }) ...
});

八、多媒体:audio / video / source

8.1 <audio>

html 复制代码
<audio controls preload="metadata" loop>
  <source src="./media/song.mp3" type="audio/mpeg">
  <source src="./media/song.ogg" type="audio/ogg">
  您的浏览器不支持音频播放,<a href="./media/song.mp3">点击下载</a>。
</audio>

8.2 <video>

html 复制代码
<video
  controls
  width="640"
  height="360"
  poster="./img/poster.jpg"
  preload="metadata"
  playsinline
  muted
>
  <source src="./media/demo.webm" type="video/webm">
  <source src="./media/demo.mp4"  type="video/mp4">
  <track kind="subtitles" src="./media/demo.zh.vtt" srclang="zh" label="中文" default>
  您的浏览器不支持视频播放。
</video>

关键属性表:

属性 说明
controls 显示播放控件
autoplay 自动播放(多数浏览器要求同时有 muted)
muted 静音
loop 循环
preload none / metadata / auto
poster 视频封面图
playsinline iOS 内联播放,不自动全屏
crossorigin 跨域设置

8.3 用 JS 控制播放

javascript 复制代码
const video = document.querySelector('video');

video.play();               // 播放(返回 Promise)
video.pause();              // 暂停
video.currentTime = 30;     // 跳到第 30 秒
video.volume = 0.5;         // 音量 0~1
video.muted = true;         // 静音
console.log(video.duration);     // 总时长(秒)
console.log(video.paused);       // 是否暂停

video.addEventListener('timeupdate', () => {
  console.log(video.currentTime);
});
video.addEventListener('ended', () => {
  console.log('播放结束');
});

8.4 字幕 <track>(WebVTT)

demo.zh.vtt 文件格式:

vtt 复制代码
WEBVTT

00:00:00.000 --> 00:00:03.000
大家好,欢迎来到 HTML5 教程。

00:00:03.500 --> 00:00:07.000
本节我们讲解多媒体标签。

九、全局属性与 data-* 自定义数据

全局属性:所有 HTML 元素都可以使用的属性。

属性 说明
id 唯一标识,一页中不可重复
class 类名,可多个,空格分隔
style 行内样式(少用)
title 悬停提示
hidden 隐藏元素(等价 display:none)
tabindex Tab 键顺序,0 可聚焦,-1 不可 Tab 但可 JS 聚焦
contenteditable 是否可编辑,true 使其变成富文本容器
draggable 是否可拖拽
spellcheck 拼写检查
lang 语言
dir 文字方向 ltr / rtl
accesskey 快捷键
data-* 自定义数据

示例:

html 复制代码
<div id="app" class="container theme-dark" data-user-id="1024" data-role="admin" hidden>
  <p contenteditable="true">这段文字可以直接编辑</p>
  <p tabindex="0">可以按 Tab 聚焦</p>
  <p title="这是提示">鼠标悬停我</p>
</div>

data-* 在 JS 中读取:

javascript 复制代码
const app = document.querySelector('#app');

// 读取:驼峰命名
console.log(app.dataset.userId);  // "1024"
console.log(app.dataset.role);    // "admin"

// 写入
app.dataset.status = 'active';    // 变成 data-status="active"

// 删除
delete app.dataset.role;

CSS 中也能用:

css 复制代码
[data-role="admin"] { border: 2px solid gold; }
[data-status="active"]::after { content: " ●"; color: green; }

data-* 是 HTML 与 JS/CSS 通信的桥梁,Vue / React 的很多底层实现都依赖它。


十、HTML5 新 API 概览

这些是 HTML5 带来的、由 JavaScript 调用的能力(后续篇章会深入)。

10.1 Web Storage(本地存储)

javascript 复制代码
// localStorage:永久保存,除非手动清除
localStorage.setItem('token', 'abc123');
console.log(localStorage.getItem('token'));  // "abc123"
localStorage.removeItem('token');
localStorage.clear();

// 存对象要序列化
localStorage.setItem('user', JSON.stringify({ name: 'Tom', age: 18 }));
const user = JSON.parse(localStorage.getItem('user'));

// sessionStorage:关闭标签页即清空
sessionStorage.setItem('draft', '草稿内容');
对比 localStorage sessionStorage Cookie
容量 ~5MB ~5MB ~4KB
生命周期 永久 会话 可设置
随请求发送 否 否 是
跨标签共享 是 否 是

10.2 Canvas 绘图

html 复制代码
<canvas id="cv" width="400" height="200"></canvas>
<script>
  const ctx = document.getElementById('cv').getContext('2d');
  ctx.fillStyle = '#3b82f6';
  ctx.fillRect(20, 20, 150, 100);
  ctx.beginPath();
  ctx.arc(300, 80, 50, 0, Math.PI * 2);
  ctx.fillStyle = '#ef4444';
  ctx.fill();
</script>

10.3 拖放 API

html 复制代码
<div id="drag" draggable="true">拖动我</div>
<div id="drop">放到这里</div>
<script>
  drag.addEventListener('dragstart', e => e.dataTransfer.setData('text', 'hello'));
  drop.addEventListener('dragover', e => e.preventDefault());
  drop.addEventListener('drop', e => {
    e.preventDefault();
    console.log(e.dataTransfer.getData('text')); // "hello"
  });
</script>

10.4 地理位置

javascript 复制代码
navigator.geolocation.getCurrentPosition(
  pos => console.log(pos.coords.latitude, pos.coords.longitude),
  err => console.error(err.message)
);

10.5 其他重要 API

API 用途
FileReader 读取本地文件内容
FormData 表单数据打包上传
Web Worker 后台线程计算,不阻塞 UI
WebSocket 双向实时通信
History API pushState 实现 SPA 路由
IntersectionObserver 懒加载、曝光埋点
MutationObserver 监听 DOM 变化
requestAnimationFrame 高性能动画
Notification 桌面通知
Clipboard API 复制粘贴

十一、可访问性(a11y)

写 HTML 时顺手做到,成本极低、收益极高。

核心原则

  1. 语义化优先 :用 <button> 而不是 <div onclick>(前者自带键盘与焦点能力)
  2. 图片有 alt :装饰图用 alt=""
  3. 表单有 label
  4. 表格有 caption 与 scope
  5. 颜色对比度 ≥ 4.5:1
  6. 不要移除焦点轮廓(若移除请提供替代样式)
  7. ARIA 属性:当语义标签不够时补充

ARIA 常用属性

html 复制代码
<!-- 按钮只有图标时,用 aria-label 说明 -->
<button aria-label="关闭弹窗">✕</button>

<!-- 折叠面板 -->
<button aria-expanded="false" aria-controls="panel">展开</button>
<div id="panel" hidden>内容</div>

<!-- 加载状态 -->
<div aria-live="polite">正在加载...</div>

<!-- 选项卡 -->
<div role="tablist">
  <button role="tab" aria-selected="true">标签一</button>
  <button role="tab" aria-selected="false">标签二</button>
</div>

ARIA 第一法则:能用原生语义标签解决的,就不要用 ARIA。


十二、项目搭建实战:个人任务管理器骨架

现在我们用纯 HTML5 搭建一个"个人任务管理器"的完整页面骨架。CSS 与 JS 将在后续篇章补全。

12.1 目录结构

复制代码
task-manager/
├── index.html              # 主页面
├── favicon.ico
├── css/
│   ├── reset.css           # 样式重置
│   ├── variables.css       # CSS 变量
│   └── main.css            # 主样式
├── js/
│   ├── main.js             # 入口
│   ├── storage.js          # localStorage 封装
│   ├── render.js           # 渲染逻辑
│   └── events.js           # 事件绑定
├── images/
│   ├── logo.svg
│   └── empty-state.svg
├── media/
└── assets/
    └── fonts/

12.2 设计要点

  • 用语义化标签搭骨架
  • 表单使用 HTML5 原生校验
  • 用 data-* 挂载任务数据,供 JS 读取
  • 用 <template> 定义任务卡片模板
  • 用 localStorage 做数据持久化
  • 用 <dialog> 实现原生弹窗

12.3 完整 index.html

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="简洁高效的个人任务管理器,基于原生 HTML5/CSS3/JavaScript 构建">
  <meta name="theme-color" content="#3b82f6">
  <title>TaskFlow · 个人任务管理器</title>

  <link rel="icon" href="./images/logo.svg" type="image/svg+xml">
  <link rel="stylesheet" href="./css/reset.css">
  <link rel="stylesheet" href="./css/variables.css">
  <link rel="stylesheet" href="./css/main.css">
</head>

<body>
  <!-- ============ 页头 ============ -->
  <header class="app-header">
    <div class="brand">
      <img src="./images/logo.svg" alt="" width="32" height="32">
      <h1>TaskFlow</h1>
    </div>

    <nav aria-label="主导航">
      <ul class="nav-list">
        <li><a href="#all" class="nav-link is-active" data-filter="all">全部</a></li>
        <li><a href="#active" class="nav-link" data-filter="active">进行中</a></li>
        <li><a href="#done" class="nav-link" data-filter="done">已完成</a></li>
      </ul>
    </nav>

    <button type="button" id="themeToggle" class="icon-btn" aria-label="切换深色模式">
      <span aria-hidden="true">🌙</span>
    </button>
  </header>

  <!-- ============ 主体 ============ -->
  <main class="app-main">

    <!-- 添加任务表单 -->
    <section aria-labelledby="add-title" class="panel">
      <h2 id="add-title" class="sr-only">添加新任务</h2>

      <form id="taskForm" class="task-form" novalidate>
        <div class="field">
          <label for="taskTitle" class="sr-only">任务标题</label>
          <input
            type="text"
            id="taskTitle"
            name="title"
            placeholder="要做什么?按回车添加..."
            required
            minlength="1"
            maxlength="80"
            autocomplete="off"
            autofocus
          >
        </div>

        <div class="field">
          <label for="taskPriority" class="sr-only">优先级</label>
          <select id="taskPriority" name="priority">
            <option value="low">低</option>
            <option value="normal" selected>普通</option>
            <option value="high">高</option>
          </select>
        </div>

        <div class="field">
          <label for="taskDue" class="sr-only">截止日期</label>
          <input type="date" id="taskDue" name="due">
        </div>

        <button type="submit" class="btn btn-primary">添加任务</button>
      </form>

      <!-- 校验错误提示(由 JS 控制显示) -->
      <p id="formError" class="form-error" role="alert" hidden></p>
    </section>

    <!-- 任务统计 -->
    <section aria-labelledby="stats-title" class="panel stats">
      <h2 id="stats-title" class="sr-only">任务统计</h2>
      <dl class="stat-list">
        <div class="stat">
          <dt>总计</dt>
          <dd id="statTotal">0</dd>
        </div>
        <div class="stat">
          <dt>进行中</dt>
          <dd id="statActive">0</dd>
        </div>
        <div class="stat">
          <dt>已完成</dt>
          <dd id="statDone">0</dd>
        </div>
      </dl>

      <div class="progress-wrap">
        <label for="progressBar" class="sr-only">完成进度</label>
        <progress id="progressBar" value="0" max="100">0%</progress>
      </div>
    </section>

    <!-- 任务列表 -->
    <section aria-labelledby="list-title" class="panel">
      <div class="panel-head">
        <h2 id="list-title">我的任务</h2>
        <button type="button" id="clearDone" class="btn btn-ghost">清除已完成</button>
      </div>

      <ul id="taskList" class="task-list" aria-live="polite">
        <!-- 任务项由 JS 渲染,或首次打开时用下面的静态示例 -->
        <li class="task-item" data-id="1" data-priority="high" data-done="false">
          <label class="task-check">
            <input type="checkbox" class="task-toggle">
            <span class="checkmark" aria-hidden="true"></span>
            <span class="task-title">完成 HTML5 第一篇学习</span>
          </label>
          <div class="task-meta">
            <span class="badge badge-high">高</span>
            <time datetime="2025-01-20">1 月 20 日</time>
          </div>
          <button type="button" class="icon-btn task-delete" aria-label="删除任务">🗑</button>
        </li>
      </ul>

      <!-- 空状态 -->
      <div id="emptyState" class="empty-state" hidden>
        <img src="./images/empty-state.svg" alt="" width="160" height="120">
        <p>还没有任务,先添加一个吧 ✨</p>
      </div>
    </section>
  </main>

  <!-- ============ 页脚 ============ -->
  <footer class="app-footer">
    <p>
      &copy; 2025 TaskFlow ·
      使用原生 <abbr title="HyperText Markup Language 5">HTML5</abbr> 构建
    </p>
    <address>
      反馈请发至 <a href="mailto:hi@taskflow.dev">hi@taskflow.dev</a>
    </address>
  </footer>

  <!-- ============ 任务模板 ============ -->
  <template id="taskTemplate">
    <li class="task-item" data-id="" data-priority="normal" data-done="false">
      <label class="task-check">
        <input type="checkbox" class="task-toggle">
        <span class="checkmark" aria-hidden="true"></span>
        <span class="task-title"></span>
      </label>
      <div class="task-meta">
        <span class="badge"></span>
        <time></time>
      </div>
      <button type="button" class="icon-btn task-delete" aria-label="删除任务">🗑</button>
    </li>
  </template>

  <!-- ============ 编辑弹窗(原生 dialog) ============ -->
  <dialog id="editDialog" class="dialog">
    <form method="dialog" class="dialog-form">
      <h2>编辑任务</h2>

      <label for="editTitle">标题</label>
      <input type="text" id="editTitle" name="title" maxlength="80" required>

      <label for="editPriority">优先级</label>
      <select id="editPriority" name="priority">
        <option value="low">低</option>
        <option value="normal">普通</option>
        <option value="high">高</option>
      </select>

      <label for="editDue">截止日期</label>
      <input type="date" id="editDue" name="due">

      <menu class="dialog-actions">
        <button type="button" id="dialogCancel" class="btn btn-ghost">取消</button>
        <button type="submit" id="dialogSave" class="btn btn-primary">保存</button>
      </menu>
    </form>
  </dialog>

  <!-- ============ 脚本 ============ -->
  <script src="./js/storage.js" defer></script>
  <script src="./js/render.js" defer></script>
  <script src="./js/events.js" defer></script>
  <script src="./js/main.js" defer></script>
</body>
</html>

12.4 骨架中的 HTML5 知识点索引

用到的技术 出现位置
<!DOCTYPE html> + lang 第 1~2 行
meta charset / viewport / description / theme-color head
link rel="icon" head
header / nav / main / section / footer 整体结构
h1 / h2 层级 各区块标题
sr-only 隐藏标题(视觉隐藏但可读) 多处
aria-label / aria-labelledby / aria-live / aria-hidden / role="alert" 无障碍
form + novalidate 添加表单
input type="text" + required + minlength + maxlength 标题输入
input type="date" 截止日期
select + option 优先级
input type="checkbox" 任务勾选
input type="email"(页脚 mailto) 联系方式
progress 完成进度
dl / dt / dd 统计信息
ul / li 任务列表、导航
data-id / data-priority / data-done 任务数据挂载
time datetime 截止日期
abbr title 页脚 HTML5 缩写
address 页脚联系信息
<template> 任务卡片模板
<dialog> 编辑弹窗
<menu> 弹窗按钮组
hidden 属性 空状态、错误提示
defer 脚本加载 底部脚本
autocomplete="off" / autofocus 输入框
&copy; 实体 页脚

12.5 配套 css/variables.css(预览,第二篇详解)

css 复制代码
:root {
  /* 颜色 */
  --color-primary: #3b82f6;
  --color-primary-dark: #2563eb;
  --color-danger: #ef4444;
  --color-success: #22c55e;
  --color-warning: #f59e0b;

  --bg-page: #f8fafc;
  --bg-card: #ffffff;
  --bg-hover: #f1f5f9;

  --text-primary: #0f172a;
  --text-secondary: #64748b;
  --text-muted: #94a3b8;

  --border-color: #e2e8f0;

  /* 圆角 */
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;

  /* 阴影 */
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08);

  /* 间距 */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
}

/* 深色主题 */
[data-theme="dark"] {
  --bg-page: #0f172a;
  --bg-card: #1e293b;
  --bg-hover: #334155;
  --text-primary: #f1f5f9;
  --text-secondary: #cbd5e1;
  --border-color: #334155;
}

12.6 配套 css/reset.css(基础重置)

css 复制代码
*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: system-ui, -apple-system, "Segoe UI", "PingFang SC",
               "Microsoft YaHei", sans-serif;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

a { color: inherit; text-decoration: none; }

ul, ol { list-style: none; }

button { background: none; border: none; cursor: pointer; }

/* 屏幕阅读器专用隐藏类 */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

12.7 js/storage.js 预览(第四、五篇详解)

javascript 复制代码
// localStorage 的简单封装,避免到处写 JSON.parse
const STORAGE_KEY = 'taskflow.tasks';

export const storage = {
  load() {
    try {
      return JSON.parse(localStorage.getItem(STORAGE_KEY)) ?? [];
    } catch {
      return [];
    }
  },
  save(tasks) {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(tasks));
  }
};

12.8 运行方式

  1. 新建 task-manager 文件夹,按上面结构建好目录
  2. 把 index.html、reset.css、variables.css、storage.js 等文件写入对应位置
  3. 用 VS Code + Live Server 插件 打开 index.html,或直接双击用浏览器打开
  4. 打开 DevTools(F12):
    • Elements 面板查看 DOM 结构
    • Application → Local Storage 查看本地存储
    • Lighthouse 面板跑一次可访问性评分

十三、本篇小结与练习

知识点回顾

模块 核心要点
文档骨架 doctype、lang、meta charset/viewport、script 的 defer/async
语义化 header/nav/main/article/section/aside/footer/figure/details
文本 h1~h6、p、strong/em、mark、code/pre、实体字符
列表表格 ul/ol/dl、table + thead/tbody/tfoot/caption/scope/colspan
链接图片 a 的 target/rel/download、img 的 alt/loading/srcset、picture
表单 全部 input type、label 绑定、原生校验、fieldset/legend、datalist
多媒体 audio/video/source/track、常用属性与 JS 控制
全局属性 data-*、hidden、contenteditable、tabindex
新 API Storage、Canvas、拖放、地理定位等概览
可访问性 alt、label、aria-*、对比度

动手练习

  1. 基础 :写一个"个人简历"页面,包含 header(姓名+联系方式)、main(article 分教育/工作经历,用 time 标时间)、footer,图片使用 figure + figcaption。
  2. 进阶 :写一个"注册表单",要求用到 email、tel(带 pattern)、date、range、color、file、checkbox、radio、datalist,并全部用 label 绑定,用 fieldset + legend 分组。
  3. 挑战 :用 <details> + <table> 做一个"FAQ + 价格对比表",要求 caption、scope、colspan 齐全,并用 Lighthouse 检查可访问性 ≥ 90 分。

常见坑清单

  • ❌ 忘记 charset → 中文乱码
  • ❌ ul 里直接放 div → 结构非法
  • ❌ label 的 for 与 input 的 id 不匹配 → 点击无效
  • ❌ <button> 在表单内不写 type → 意外提交
  • ❌ 图片不写 alt → 无障碍不合格
  • ❌ target="_blank" 不加 rel="noopener" → 安全漏洞
  • ❌ 用 div 代替 button → 失去键盘可访问性
  • ❌ 脚本写在 head 且不加 defer → 拿不到 DOM

下一篇预告

第二篇:CSS3 全部知识点

  • 选择器全解(基础 / 组合 / 伪类 / 伪元素 / 属性选择器)
  • 层叠、继承、优先级计算
  • 盒模型、box-sizing、外边距塌陷
  • 现代布局:Flexbox 全属性 + Grid 全属性
  • 定位、层叠上下文、BFC
  • 过渡、动画、变形(transform)
  • 媒体查询与响应式设计
  • CSS 变量、clamp()、容器查询
  • 把本项目的 main.css 完整实现出来

请把上面的 index.html 保存好,下一篇我们将把它变成一个漂亮的成品界面。 🚀

相关推荐
百度一下吧1 小时前
CSS 伪类使用与实践:从入门到进阶
前端·css
hunterandroid1 小时前
android方案 : Multiplatform 跨平台开发实战:一套代码,多端运行
android·前端
百度一下吧1 小时前
CSS3 之后新增的特性:从 CSS4 到现代 CSS 的演进
前端·css·css3
爱喝热水的呀哈喽1 小时前
hm探查。
java·前端·人工智能
2603_965896621 小时前
JS ES6常用新特性|let/const、解构赋值、展开运算符
前端·javascript·es6
衡石科技1 小时前
一个门户只保留一个智能助理:衡石嵌入式 Data Agent 的运行与渲染边界
前端·javascript·html·data agent
Hilaku1 小时前
一个前端工程师除了写代码,还能靠什么赚钱?
前端·javascript·程序员
程序员Sunday1 小时前
JavaScript 闭包是什么?为什么变量没有被释放,什么时候会内存泄漏?
前端·javascript