HTML5 新特性
概述
HTML5 是 HTML(超文本标记语言)的第五个主要版本,由 W3C 和 WHATWG 共同制定,于 2014 年正式发布。它不仅仅是对 HTML 标签的更新,更是一次Web 平台能力的全面升级,涵盖了语义化标签、多媒体支持、本地存储、设备访问等众多方面。
在现代前端开发中,HTML5 的新特性已经成为基础设施。无论是使用 React、Vue 还是原生开发,你都会用到语义化标签、本地存储、表单验证等能力。同时,HTML5 新特性也是前端面试的高频考点。
语义化标签
什么是语义化?
语义化就是让标签的含义与它包裹的内容一致。在 HTML5 之前,页面布局几乎全部依赖 <div> 和 <span>,代码看起来就像一堆"无意义的盒子":
<!-- HTML4 时代的典型布局:满屏 div -->
<div class="header">
<div class="nav">...</div>
</div>
<div class="content">
<div class="article">...</div>
<div class="sidebar">...</div>
</div>
<div class="footer">...</div>
HTML5 引入了一组语义化标签,让代码"会说话":
<!-- HTML5 语义化布局:标签即含义 -->
<header>
<nav>...</nav>
</header>
<main>
<article>...</article>
<aside>...</aside>
</main>
<footer>...</footer>
语义化的好处
常用语义化标签一览
| 标签 | 语义 | 说明 |
|---|---|---|
<header> | 页头 / 区块头部 | 通常包含导航、Logo、标题等 |
<nav> | 导航区域 | 主要导航链接的容器 |
<main> | 主体内容 | 页面的核心内容,每个页面只能有一个 |
<article> | 独立内容块 | 可以独立传播的完整内容(文章、帖子、评论) |
<section> | 内容分区 | 按主题分组的内容区块,通常有标题 |
<aside> | 侧边栏 / 附加信息 | 与主内容相关但非核心的内容 |
<footer> | 页脚 / 区块底部 | 通常包含版权、联系方式、链接等 |
<figure> | 独立引用内容 | 图片、图表、代码片段等,配合 <figcaption> 使用 |
<figcaption> | 图片说明 | 为 <figure> 提供标题或描述 |
<details> | 可展开的详情 | 用户可以点击展开/收起的内容区域 |
<summary> | 详情摘要 | <details> 的标题,点击可切换展开状态 |
<mark> | 高亮文本 | 标记需要引起注意的文本 |
<time> | 时间 | 表示日期或时间,机器可读 |
完整页面结构示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>我的博客</title>
</head>
<body>
<header>
<h1>我的技术博客</h1>
<nav>
<ul>
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
<li><a href="/contact">联系</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h2>理解 HTML5 语义化</h2>
<time datetime="2025-01-15">2025 年 1 月 15 日</time>
<section>
<h3>什么是语义化</h3>
<p>语义化是指使用恰当的 HTML 标签来表达内容的含义...</p>
</section>
<section>
<h3>语义化的好处</h3>
<p>提升可访问性、有利于 SEO...</p>
</section>
<figure>
<img src="semantic.png" alt="语义化标签布局示意图">
<figcaption>图 1:HTML5 语义化标签的典型页面布局</figcaption>
</figure>
</article>
<aside>
<h3>推荐阅读</h3>
<ul>
<li><a href="#">CSS Grid 布局详解</a></li>
<li><a href="#">JavaScript 事件循环</a></li>
</ul>
</aside>
</main>
<footer>
<p>© 2025 我的技术博客. All rights reserved.</p>
</footer>
</body>
</html>
<article> vs <section> 的区别
这两个标签容易混淆,记住这个核心判断标准:
<!-- article:独立完整的内容 -->
<article>
<h2>CSS Grid 入门教程</h2>
<p>CSS Grid 是一种二维布局系统...</p>
</article>
<!-- section:按主题划分的区块 -->
<section>
<h2>基本概念</h2>
<p>Grid 容器和 Grid 项目...</p>
</section>
<section>
<h2>常用属性</h2>
<p>grid-template-columns...</p>
</section>
<details> 和 <summary>:原生折叠面板
无需 JavaScript 即可实现展开/收起效果:
<details>
<summary>点击查看更多信息</summary>
<p>这是被折叠的详细内容,点击 summary 可以展开或收起。</p>
<p>这是一个纯 HTML 实现的折叠面板,不需要任何 JavaScript。</p>
</details>
<!-- 默认展开 -->
<details open>
<summary>常见问题</summary>
<p>Q: HTML5 什么时候发布的?</p>
<p>A: 2014 年由 W3C 正式推荐。</p>
</details>
增强的表单功能
HTML5 对表单进行了大幅增强,新增了许多输入类型和验证属性,减少了对 JavaScript 的依赖。
新增 input 类型
| 类型 | 说明 | 示例 |
|---|---|---|
email | 邮箱输入,自动校验格式 | <input type="email"> |
url | URL 输入,自动校验格式 | <input type="url"> |
tel | 电话号码,移动端弹出数字键盘 | <input type="tel"> |
search | 搜索框,部分浏览器带清除按钮 | <input type="search"> |
number | 数字输入,带增减按钮 | <input type="number" min="0" max="100"> |
range | 滑块选择器 | <input type="range" min="0" max="100"> |
color | 颜色选择器 | <input type="color" value="#ff0000"> |
date | 日期选择器 | <input type="date"> |
time | 时间选择器 | <input type="time"> |
month | 月份选择器 | <input type="month"> |
week | 周选择器 | <input type="week"> |
datetime-local | 日期时间选择器 | <input type="datetime-local"> |
完整表单示例
<form>
<h3>用户注册</h3>
<!-- 邮箱:自动验证格式 -->
<label for="email">邮箱:</label>
<input type="email" id="email" placeholder="your@email.com" required>
<!-- 年龄:数字输入,限制范围 -->
<label for="age">年龄:</label>
<input type="number" id="age" min="1" max="150" step="1">
<!-- 生日:日期选择器 -->
<label for="birthday">生日:</label>
<input type="date" id="birthday">
<!-- 个人主页:URL 验证 -->
<label for="website">个人主页:</label>
<input type="url" id="website" placeholder="https://example.com">
<!-- 满意度:滑块 -->
<label for="satisfaction">满意度:</label>
<input type="range" id="satisfaction" min="0" max="10" value="5">
<!-- 喜欢的颜色:颜色选择器 -->
<label for="favcolor">喜欢的颜色:</label>
<input type="color" id="favcolor" value="#3498db">
<button type="submit">提交</button>
</form>
新增表单属性
| 属性 | 说明 | 示例 |
|---|---|---|
placeholder | 占位提示文字 | <input placeholder="请输入..."> |
required | 必填字段 | <input required> |
pattern | 正则验证 | <input pattern="[0-9]{6}" title="请输入6位数字"> |
autofocus | 页面加载时自动聚焦 | <input autofocus> |
autocomplete | 自动补全 | <input autocomplete="off"> |
min / max | 数值范围限制 | <input type="number" min="0" max="100"> |
step | 数值步进 | <input type="number" step="0.01"> |
multiple | 允许多选(文件、邮箱) | <input type="file" multiple> |
form | 关联外部表单 | <input form="myForm"> |
原生表单验证
HTML5 提供了内置的表单验证机制,无需 JavaScript 即可完成常见验证:
<form>
<!-- required:必填验证 -->
<input type="text" required placeholder="必填字段">
<!-- pattern:正则验证(手机号) -->
<input
type="tel"
pattern="1[3-9]\d{9}"
title="请输入有效的手机号码"
placeholder="手机号"
>
<!-- minlength / maxlength:长度限制 -->
<input
type="password"
minlength="8"
maxlength="20"
placeholder="密码(8-20位)"
required
>
<!-- min / max:数值范围 -->
<input type="number" min="18" max="65" placeholder="年龄(18-65)">
<button type="submit">提交</button>
</form>
JavaScript 验证 API
HTML5 还提供了配套的 JavaScript 验证接口:
const form = document.querySelector('form');
const emailInput = document.querySelector('#email');
// 检查表单整体有效性
console.log(form.checkValidity()); // true 或 false
// 检查单个字段有效性
console.log(emailInput.validity.valid); // 是否有效
console.log(emailInput.validity.typeMismatch); // 类型不匹配
console.log(emailInput.validity.valueMissing); // 必填项为空
console.log(emailInput.validity.patternMismatch); // 正则不匹配
// 自定义错误提示
emailInput.addEventListener('invalid', (e) => {
if (emailInput.validity.typeMismatch) {
emailInput.setCustomValidity('请输入有效的邮箱地址,例如 name@example.com');
}
});
// 清除自定义错误(input 事件中清除)
emailInput.addEventListener('input', () => {
emailInput.setCustomValidity('');
});
<datalist>:输入建议列表
为 <input> 提供预定义的候选项,用户可以选择也可以自行输入:
<label for="browser">你常用的浏览器:</label>
<input list="browsers" id="browser" placeholder="输入或选择">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
<option value="Edge">
</datalist>
<output>:计算结果展示
用于展示计算或操作的结果:
<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
<input type="number" id="a" value="10"> +
<input type="number" id="b" value="20"> =
<output name="result" for="a b">30</output>
</form>
多媒体支持
在 HTML5 之前,网页播放音视频需要依赖 Flash 等第三方插件。HTML5 引入了原生的 <audio> 和 <video> 标签,让多媒体成为 Web 的一等公民。
<video> 视频
<!-- 基本用法 -->
<video src="movie.mp4" controls width="640" height="360">
您的浏览器不支持 video 标签。
</video>
<!-- 多格式兼容 + 完整属性 -->
<video
width="640"
height="360"
controls
poster="cover.jpg"
preload="metadata"
>
<source src="movie.webm" type="video/webm">
<source src="movie.mp4" type="video/mp4">
<track src="subtitles_zh.vtt" kind="subtitles" srclang="zh" label="中文字幕">
您的浏览器不支持 video 标签。
</video>
常用属性:
| 属性 | 说明 | 示例 |
|---|---|---|
controls | 显示播放控件 | <video controls> |
autoplay | 自动播放(通常需配合 muted) | <video autoplay muted> |
muted | 静音 | <video muted> |
loop | 循环播放 | <video loop> |
poster | 视频封面图 | <video poster="cover.jpg"> |
preload | 预加载策略:auto / metadata / none | <video preload="metadata"> |
width / height | 视频尺寸 | <video width="640" height="360"> |
<audio> 音频
<!-- 基本用法 -->
<audio controls>
<source src="music.ogg" type="audio/ogg">
<source src="music.mp3" type="audio/mpeg">
您的浏览器不支持 audio 标签。
</audio>
JavaScript 多媒体 API
const video = document.querySelector('video');
// 播放控制
video.play(); // 播放
video.pause(); // 暂停
video.currentTime = 30; // 跳转到第 30 秒
// 读取状态
console.log(video.duration); // 总时长(秒)
console.log(video.currentTime); // 当前播放位置
console.log(video.paused); // 是否暂停
console.log(video.volume); // 音量(0-1)
console.log(video.playbackRate); // 播放速率
// 事件监听
video.addEventListener('play', () => console.log('开始播放'));
video.addEventListener('pause', () => console.log('已暂停'));
video.addEventListener('ended', () => console.log('播放结束'));
video.addEventListener('timeupdate', () => {
console.log('当前进度:', video.currentTime);
});
video.addEventListener('error', (e) => {
console.error('播放出错:', e);
});
现代浏览器为了用户体验,对自动播放有严格限制:
- 有声自动播放:大多数浏览器会阻止
- 静音自动播放:通常允许(
autoplay muted) - 用户交互后:调用
video.play()可以正常播放
所以视频自动播放时一定要加 muted 属性。
本地存储
HTML5 之前,浏览器端存储数据主要依赖 Cookie。HTML5 引入了 Web Storage(localStorage 和 sessionStorage),提供了更大容量、更简单的本地存储方案。
三者对比
| 对比维度 | Cookie | localStorage | sessionStorage |
|---|---|---|---|
| 容量 | ~4KB | ~5MB | ~5MB |
| 生命周期 | 可设过期时间 | 永久,除非手动清除 | 标签页关闭即清除 |
| 作用域 | 同源 + 路径 | 同源共享 | 同源 + 同标签页 |
| 随请求发送 | 自动发送到服务器 | 不会 | 不会 |
| API | document.cookie(不友好) | 简洁的键值对 API | 简洁的键值对 API |
| 适用场景 | 身份认证(token) | 持久化用户设置 | 临时表单数据 |
localStorage 基本用法
// 存储数据
localStorage.setItem('username', '张三');
localStorage.setItem('theme', 'dark');
// 读取数据
const username = localStorage.getItem('username'); // '张三'
// 删除单条数据
localStorage.removeItem('theme');
// 清空所有数据
localStorage.clear();
// 获取存储的数据条数
console.log(localStorage.length); // 1
// 按索引获取 key
console.log(localStorage.key(0)); // 'username'
存储复杂数据
localStorage 只能存储字符串,存储对象和数组需要序列化:
// 存储对象
const user = { name: '张三', age: 25, hobbies: ['编程', '阅读'] };
localStorage.setItem('user', JSON.stringify(user));
// 读取对象
const stored = JSON.parse(localStorage.getItem('user'));
console.log(stored.name); // '张三'
console.log(stored.hobbies); // ['编程', '阅读']
- 不要存储敏感信息(密码、token 等),localStorage 没有加密,任何 JS 脚本都能读取
- 不要存储过大的数据,超过容量限制会抛出
QuotaExceededError异常 - 操作是同步的,存取大量数据可能阻塞主线程
- 仅支持字符串,存储对象时需要
JSON.stringify/JSON.parse
sessionStorage 基本用法
API 与 localStorage 完全一致,唯一区别是数据在标签页关闭后自动清除:
// 典型场景:保存表单临时数据,防止刷新丢失
const formData = {
title: document.getElementById('title').value,
content: document.getElementById('content').value,
};
sessionStorage.setItem('draft', JSON.stringify(formData));
// 页面加载时恢复
window.addEventListener('load', () => {
const draft = sessionStorage.getItem('draft');
if (draft) {
const data = JSON.parse(draft);
document.getElementById('title').value = data.title;
document.getElementById('content').value = data.content;
}
});
监听存储变化
当同源的其他标签页修改了 localStorage,当前页可以通过 storage 事件感知:
// 监听其他标签页对 localStorage 的修改
window.addEventListener('storage', (e) => {
console.log('变更的键:', e.key);
console.log('旧值:', e.oldValue);
console.log('新值:', e.newValue);
console.log('来源页面:', e.url);
});
storage 事件可以用于同源标签页之间的简单通信。比如用户在 A 标签页退出登录,B 标签页通过 storage 事件监听到 token 被清除,自动跳转到登录页。
地理定位 API
HTML5 的 Geolocation API 允许网页获取用户的地理位置信息(需要用户授权)。
获取当前位置
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(
// 成功回调
(position) => {
console.log('纬度:', position.coords.latitude);
console.log('经度:', position.coords.longitude);
console.log('精度:', position.coords.accuracy, '米');
console.log('海拔:', position.coords.altitude); // 可能为 null
console.log('速度:', position.coords.speed); // 可能为 null
console.log('时间戳:', position.timestamp);
},
// 失败回调
(error) => {
switch (error.code) {
case error.PERMISSION_DENIED:
console.log('用户拒绝了位置请求');
break;
case error.POSITION_UNAVAILABLE:
console.log('位置信息不可用');
break;
case error.TIMEOUT:
console.log('请求超时');
break;
}
},
// 配置选项
{
enableHighAccuracy: true, // 高精度模式
timeout: 5000, // 超时时间(毫秒)
maximumAge: 0, // 不使用缓存
}
);
} else {
console.log('浏览器不支持地理定位');
}
持续监听位置变化
// 开始监听
const watchId = navigator.geolocation.watchPosition(
(position) => {
console.log('位置更新:', position.coords.latitude, position.coords.longitude);
},
(error) => {
console.error('定位失败:', error.message);
}
);
// 停止监听
navigator.geolocation.clearWatch(watchId);
拖放 API(Drag and Drop)
HTML5 提供了原生的拖放功能,让元素可以通过鼠标拖动进行交互。
拖放流程
基本实现
<div id="drag-item" draggable="true" style="width:100px;height:100px;background:#3498db;color:white;text-align:center;line-height:100px;">
拖动我
</div>
<div id="drop-zone" style="width:300px;height:200px;border:2px dashed #ccc;margin-top:20px;text-align:center;line-height:200px;">
放到这里
</div>
const dragItem = document.getElementById('drag-item');
const dropZone = document.getElementById('drop-zone');
// 拖动开始:设置要传递的数据
dragItem.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', '这是拖动的数据');
e.dataTransfer.effectAllowed = 'move';
dragItem.style.opacity = '0.5';
});
// 拖动结束:恢复样式
dragItem.addEventListener('dragend', () => {
dragItem.style.opacity = '1';
});
// 必须阻止 dragover 的默认行为,否则 drop 事件不会触发
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.style.borderColor = '#3498db';
});
// 拖动离开:恢复样式
dropZone.addEventListener('dragleave', () => {
dropZone.style.borderColor = '#ccc';
});
// 放下:获取传递的数据
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
const data = e.dataTransfer.getData('text/plain');
dropZone.textContent = `接收到: ${data}`;
dropZone.style.borderColor = '#2ecc71';
dropZone.appendChild(dragItem);
});
拖放事件一览
| 事件 | 触发对象 | 触发时机 |
|---|---|---|
dragstart | 被拖动元素 | 开始拖动时 |
drag | 被拖动元素 | 拖动过程中持续触发 |
dragend | 被拖动元素 | 拖动结束时 |
dragenter | 目标区域 | 拖动元素进入目标区域 |
dragover | 目标区域 | 拖动元素在目标区域上方移动 |
dragleave | 目标区域 | 拖动元素离开目标区域 |
drop | 目标区域 | 在目标区域释放拖动元素 |
- 要使元素可拖动,必须设置
draggable="true"属性 - 必须在
dragover事件中调用e.preventDefault(),否则drop事件不会触发 - 图片和链接默认是可拖动的,不需要额外设置
Web Workers:多线程
JavaScript 是单线程的,复杂计算会阻塞 UI 渲染。HTML5 的 Web Workers 允许在后台线程中运行 JavaScript,不会影响页面响应。
基本用法
主线程代码(main.js):
// 创建 Worker
const worker = new Worker('worker.js');
// 向 Worker 发送消息
worker.postMessage({ type: 'calculate', data: 1000000 });
// 接收 Worker 的计算结果
worker.onmessage = (e) => {
console.log('Worker 计算结果:', e.data);
};
// 错误处理
worker.onerror = (e) => {
console.error('Worker 出错:', e.message);
};
// 终止 Worker
// worker.terminate();
Worker 线程代码(worker.js):
// 接收主线程的消息
self.onmessage = (e) => {
const { type, data } = e.data;
if (type === 'calculate') {
// 执行耗时计算(不会阻塞 UI)
let sum = 0;
for (let i = 0; i < data; i++) {
sum += Math.sqrt(i);
}
// 将结果发送回主线程
self.postMessage(sum);
}
};
Worker 的限制
| 能力 | 是否支持 | 说明 |
|---|---|---|
| DOM 操作 | ❌ | 无法访问 document、window |
console.log | ✅ | 可以使用 |
XMLHttpRequest / fetch | ✅ | 可以发送网络请求 |
setTimeout / setInterval | ✅ | 可以使用定时器 |
localStorage | ❌ | 无法访问 |
navigator | ✅(部分) | 可以使用部分属性 |
| 导入脚本 | ✅ | 通过 importScripts() |
- 大量数学计算(如加密、数据分析)
- 大文件的解析处理(如 CSV、JSON)
- 图像处理(像素级操作)
- 排序、搜索大规模数据
WebSocket:全双工通信
传统的 HTTP 通信是"请求—响应"模式,客户端发起请求,服务器才能返回数据。WebSocket 建立的是一个持久连接,服务器可以主动向客户端推送数据。
基本用法
// 创建 WebSocket 连接
const ws = new WebSocket('wss://example.com/socket');
// 连接建立成功
ws.addEventListener('open', () => {
console.log('WebSocket 连接已建立');
ws.send('Hello Server!');
ws.send(JSON.stringify({ type: 'chat', message: '你好' }));
});
// 接收服务器消息
ws.addEventListener('message', (e) => {
console.log('收到消息:', e.data);
const data = JSON.parse(e.data);
// 处理消息...
});
// 连接关闭
ws.addEventListener('close', (e) => {
console.log('连接已关闭:', e.code, e.reason);
});
// 连接错误
ws.addEventListener('error', (e) => {
console.error('WebSocket 错误:', e);
});
// 主动关闭连接
// ws.close();
WebSocket 连接状态
console.log(ws.readyState);
// 0 - CONNECTING:正在连接
// 1 - OPEN:连接已建立
// 2 - CLOSING:正在关闭
// 3 - CLOSED:连接已关闭
适用场景
| 场景 | 说明 |
|---|---|
| 即时通讯 | 聊天应用、客服系统 |
| 实时数据 | 股票行情、体育比分 |
| 协同编辑 | 多人文档编辑、在线白板 |
| 游戏 | 多人在线游戏的实时交互 |
| 通知推送 | 系统通知、消息提醒 |
History API
HTML5 增强了浏览器历史记录管理能力,使得**单页应用(SPA)**可以在不刷新页面的情况下改变 URL,这是 Vue Router、React Router 等前端路由库的基础。
核心方法
// 1. pushState:添加一条新的历史记录
// 参数:state 对象、标题(通常传空字符串)、URL
history.pushState({ page: 'about' }, '', '/about');
// URL 变成了 /about,但页面不会刷新
// 2. replaceState:替换当前的历史记录(不会新增)
history.replaceState({ page: 'home' }, '', '/home');
// 3. back / forward / go:导航操作
history.back(); // 等同于点击浏览器"后退"按钮
history.forward(); // 等同于点击浏览器"前进"按钮
history.go(-2); // 后退 2 步
监听历史记录变化
// popstate 事件:用户点击"前进"/"后退"按钮时触发
window.addEventListener('popstate', (e) => {
console.log('URL 变化:', location.pathname);
console.log('状态对象:', e.state);
// 根据新的 URL 渲染对应内容
});
简易 SPA 路由示例
// 路由配置
const routes = {
'/': '<h1>首页</h1><p>欢迎来到首页</p>',
'/about': '<h1>关于</h1><p>这是关于页面</p>',
'/contact': '<h1>联系</h1><p>这是联系页面</p>',
};
// 渲染页面
function render(path) {
const content = routes[path] || '<h1>404</h1><p>页面未找到</p>';
document.getElementById('app').innerHTML = content;
}
// 导航函数
function navigate(path) {
history.pushState({ path }, '', path);
render(path);
}
// 监听浏览器前进/后退
window.addEventListener('popstate', (e) => {
render(location.pathname);
});
// 拦截链接点击
document.addEventListener('click', (e) => {
if (e.target.tagName === 'A' && e.target.getAttribute('href').startsWith('/')) {
e.preventDefault();
navigate(e.target.getAttribute('href'));
}
});
// 初始渲染
render(location.pathname);
前端路由有两种模式:
- Hash 模式(
#/about):利用 URL 的 hash 部分,兼容性好,不需要服务器配置 - History 模式(
/about):利用 HTML5 的 History API,URL 更美观,但需要服务器配置将所有路由指向同一个 HTML 文件
现代项目推荐使用 History 模式。
其他实用新特性
data-* 自定义数据属性
HTML5 允许在元素上添加以 data- 为前缀的自定义属性,用于存储与元素相关的自定义数据:
<div
id="user"
data-user-id="1001"
data-role="admin"
data-last-login="2025-01-15"
>
张三
</div>
const userDiv = document.getElementById('user');
// 通过 dataset 读取(自动转为 camelCase)
console.log(userDiv.dataset.userId); // '1001'
console.log(userDiv.dataset.role); // 'admin'
console.log(userDiv.dataset.lastLogin); // '2025-01-15'
// 设置自定义数据
userDiv.dataset.status = 'online'; // 添加 data-status="online"
- HTML 中:
data-后面用连字符分隔,如data-user-id - JavaScript 中:
dataset属性自动转为 camelCase,如dataset.userId
contenteditable:可编辑内容
让任何 HTML 元素变成可编辑状态:
<!-- 可编辑的 div -->
<div contenteditable="true" style="border:1px solid #ccc; padding:10px; min-height:100px;">
点击这里开始编辑文字...
</div>
<!-- 可编辑的标题 -->
<h2 contenteditable="true">点击编辑这个标题</h2>
<progress> 和 <meter>
<!-- progress:任务进度条 -->
<label>下载进度:</label>
<progress value="70" max="100">70%</progress>
<!-- meter:度量衡(有合理范围概念) -->
<label>磁盘使用:</label>
<meter value="0.7" min="0" max="1" low="0.3" high="0.8" optimum="0.5">70%</meter>
全屏 API
const elem = document.getElementById('video-player');
// 进入全屏
elem.requestFullscreen();
// 退出全屏
document.exitFullscreen();
// 监听全屏变化
document.addEventListener('fullscreenchange', () => {
if (document.fullscreenElement) {
console.log('进入全屏:', document.fullscreenElement);
} else {
console.log('退出全屏');
}
});
页面可见性 API
检测用户是否正在查看当前页面(如切换到了其他标签页):
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
console.log('用户离开了页面');
// 暂停动画、停止轮询等
} else {
console.log('用户回到了页面');
// 恢复动画、继续轮询等
}
});
- 用户切走时暂停视频播放
- 减少后台标签页的定时器频率,节省资源
- 在线考试系统检测用户是否切屏
HTML5 新特性总结
面试高频问答
Q1:HTML5 有哪些重要的新特性?
A:HTML5 的新特性可以归纳为以下几大类:
- 语义化标签:
header、nav、main、article、section、aside、footer等 - 增强表单:新增
email、date、number、range、color等输入类型,以及placeholder、required、pattern等验证属性 - 多媒体:原生
<video>和<audio>标签,无需 Flash - 图形绘制:Canvas 2D 绘图 和 SVG
- 本地存储:
localStorage和sessionStorage - 离线应用:Service Worker(取代了 Application Cache)
- 通信能力:WebSocket 全双工通信、Server-Sent Events
- 多线程:Web Workers
- 设备访问:Geolocation、DeviceOrientation 等 API
- 其他:拖放 API、History API、全屏 API、页面可见性 API、
data-*自定义属性等
Q2:localStorage 和 sessionStorage 有什么区别?
A:两者 API 完全一致,区别在于:
- localStorage:数据永久存储,除非用户手动清除或代码删除,关闭浏览器后数据依然存在。同源的所有标签页共享数据。
- sessionStorage:数据会话级别存储,标签页关闭后自动清除。仅在当前标签页内有效,即使同源的不同标签页也互相隔离。
Q3:localStorage 和 Cookie 有什么区别?
A:
| 维度 | Cookie | localStorage |
|---|---|---|
| 容量 | ~4KB | ~5MB |
| 随请求发送 | 每次 HTTP 请求自动携带 | 不会发送到服务器 |
| 过期时间 | 可设置 expires / max-age | 永久存储,需手动删除 |
| 操作 API | document.cookie(字符串拼接,不友好) | setItem / getItem(简洁) |
| 作用域 | 同源 + 可配置 path 和 domain | 同源 |
| 适用场景 | 身份认证信息(session ID、token) | 客户端数据持久化(用户设置、缓存等) |
Q4:什么是 Web Workers?有什么限制?
A:Web Workers 允许在后台线程中运行 JavaScript 代码,不会阻塞 UI 主线程。适用于复杂计算、大数据处理等耗时任务。主要限制:
- 不能操作 DOM:无法访问
document、window、parent等对象 - 不能使用 localStorage:也无法直接访问主页面的任何数据
- 通信方式受限:只能通过
postMessage/onmessage与主线程通信 - 同源限制:Worker 脚本文件必须与主页面同源
- 资源消耗:每个 Worker 都是一个独立线程,创建过多会消耗系统资源
Q5:WebSocket 和 HTTP 有什么区别?
A:
- HTTP 是半双工的"请求—响应"模式,客户端主动请求、服务器被动回应。每次通信都需要重新建立连接(短连接)或在 keep-alive 连接上发起新请求。
- WebSocket 是全双工通信协议,建立连接后,客户端和服务器可以随时互相发送数据。连接是持久的,不需要反复握手。WebSocket 的初始握手是通过 HTTP 升级(Upgrade)完成的。
WebSocket 适合实时性要求高的场景(聊天、股票、游戏),HTTP 适合传统的请求-响应场景(页面加载、API 调用)。
Q6:HTML5 的 History API 有什么用?pushState 和 replaceState 的区别?
A:History API 让开发者可以在不刷新页面的情况下操作浏览器历史记录和地址栏 URL,这是前端 SPA 路由(如 Vue Router、React Router)的核心基础。
pushState:向历史记录栈中添加一条新记录,用户可以点击"后退"按钮回到之前的状态。replaceState:替换当前的历史记录,不会新增记录,用户点击"后退"不会回到被替换的页面。
Q7:HTML5 的语义化标签有什么好处?
A:
- 可访问性(Accessibility):屏幕阅读器可以识别
nav、main、article等标签,帮助视障用户理解页面结构和快速导航。 - SEO 优化:搜索引擎能更好地理解页面内容的层次和重点,有利于搜索排名。
- 代码可读性:开发者看到
<header>、<nav>、<footer>就能立刻理解模块作用,比满屏<div class="header">清晰得多。 - 便于维护:结构化的代码更容易修改和扩展,团队协作效率更高。
Q8:HTML5 的拖放 API 中,为什么必须在 dragover 中调用 preventDefault()?
A:浏览器默认不允许将元素放置到其他元素上(drop 事件默认被阻止)。dragover 事件的默认行为就是"阻止放置",所以必须调用 e.preventDefault() 来取消这个默认行为,告诉浏览器"这个区域允许放置元素",这样 drop 事件才能正常触发。
Q9:HTML5 有哪些方式可以实现离线存储?
A:
- localStorage / sessionStorage:存储键值对数据
- IndexedDB:浏览器端的 NoSQL 数据库,可存储大量结构化数据
- Cache API(配合 Service Worker):缓存网络请求和响应,实现离线访问
- Application Cache(已废弃,被 Service Worker 取代)
现代 PWA(渐进式 Web 应用)主要使用 Service Worker + Cache API 实现离线功能。
Q10:如何实现浏览器跨标签页通信?
A:常见方案有:
- localStorage + storage 事件:一个标签页写入 localStorage,其他同源标签页通过
storage事件监听到变化 - BroadcastChannel API:创建命名频道,同源标签页可以互相广播消息
- SharedWorker:多个标签页共享同一个 Worker,通过 Worker 中转消息
- WebSocket:通过服务器中转消息(可跨域)
- postMessage:如果标签页之间有
window.open或 iframe 关系,可以用postMessage通信
其中最简单的方案是 localStorage + storage 事件,最强大的是 BroadcastChannel API。