跳到主要内容

HTML5 新特性

概述

HTML5 是 HTML(超文本标记语言)的第五个主要版本,由 W3C 和 WHATWG 共同制定,于 2014 年正式发布。它不仅仅是对 HTML 标签的更新,更是一次Web 平台能力的全面升级,涵盖了语义化标签、多媒体支持、本地存储、设备访问等众多方面。

为什么要学 HTML5 新特性?

在现代前端开发中,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>&copy; 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">
urlURL 输入,自动校验格式<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 StoragelocalStoragesessionStorage),提供了更大容量、更简单的本地存储方案。

三者对比

对比维度CookielocalStoragesessionStorage
容量~4KB~5MB~5MB
生命周期可设过期时间永久,除非手动清除标签页关闭即清除
作用域同源 + 路径同源共享同源 + 同标签页
随请求发送自动发送到服务器不会不会
APIdocument.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); // ['编程', '阅读']
注意事项
  1. 不要存储敏感信息(密码、token 等),localStorage 没有加密,任何 JS 脚本都能读取
  2. 不要存储过大的数据,超过容量限制会抛出 QuotaExceededError 异常
  3. 操作是同步的,存取大量数据可能阻塞主线程
  4. 仅支持字符串,存储对象时需要 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 操作无法访问 documentwindow
console.log可以使用
XMLHttpRequest / fetch可以发送网络请求
setTimeout / setInterval可以使用定时器
localStorage无法访问
navigator✅(部分)可以使用部分属性
导入脚本通过 importScripts()
Worker 的适用场景
  • 大量数学计算(如加密、数据分析)
  • 大文件的解析处理(如 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 模式 vs History 模式

前端路由有两种模式:

  • 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 的新特性可以归纳为以下几大类:

  1. 语义化标签headernavmainarticlesectionasidefooter
  2. 增强表单:新增 emaildatenumberrangecolor 等输入类型,以及 placeholderrequiredpattern 等验证属性
  3. 多媒体:原生 <video><audio> 标签,无需 Flash
  4. 图形绘制:Canvas 2D 绘图 和 SVG
  5. 本地存储localStoragesessionStorage
  6. 离线应用:Service Worker(取代了 Application Cache)
  7. 通信能力:WebSocket 全双工通信、Server-Sent Events
  8. 多线程:Web Workers
  9. 设备访问:Geolocation、DeviceOrientation 等 API
  10. 其他:拖放 API、History API、全屏 API、页面可见性 API、data-* 自定义属性等

Q2:localStorage 和 sessionStorage 有什么区别?

A:两者 API 完全一致,区别在于:

  • localStorage:数据永久存储,除非用户手动清除或代码删除,关闭浏览器后数据依然存在。同源的所有标签页共享数据。
  • sessionStorage:数据会话级别存储,标签页关闭后自动清除。仅在当前标签页内有效,即使同源的不同标签页也互相隔离。

A

维度CookielocalStorage
容量~4KB~5MB
随请求发送每次 HTTP 请求自动携带不会发送到服务器
过期时间可设置 expires / max-age永久存储,需手动删除
操作 APIdocument.cookie(字符串拼接,不友好)setItem / getItem(简洁)
作用域同源 + 可配置 path 和 domain同源
适用场景身份认证信息(session ID、token)客户端数据持久化(用户设置、缓存等)

Q4:什么是 Web Workers?有什么限制?

A:Web Workers 允许在后台线程中运行 JavaScript 代码,不会阻塞 UI 主线程。适用于复杂计算、大数据处理等耗时任务。主要限制:

  1. 不能操作 DOM:无法访问 documentwindowparent 等对象
  2. 不能使用 localStorage:也无法直接访问主页面的任何数据
  3. 通信方式受限:只能通过 postMessage / onmessage 与主线程通信
  4. 同源限制:Worker 脚本文件必须与主页面同源
  5. 资源消耗:每个 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

  1. 可访问性(Accessibility):屏幕阅读器可以识别 navmainarticle 等标签,帮助视障用户理解页面结构和快速导航。
  2. SEO 优化:搜索引擎能更好地理解页面内容的层次和重点,有利于搜索排名。
  3. 代码可读性:开发者看到 <header><nav><footer> 就能立刻理解模块作用,比满屏 <div class="header"> 清晰得多。
  4. 便于维护:结构化的代码更容易修改和扩展,团队协作效率更高。

Q8:HTML5 的拖放 API 中,为什么必须在 dragover 中调用 preventDefault()?

A:浏览器默认不允许将元素放置到其他元素上(drop 事件默认被阻止)。dragover 事件的默认行为就是"阻止放置",所以必须调用 e.preventDefault() 来取消这个默认行为,告诉浏览器"这个区域允许放置元素",这样 drop 事件才能正常触发。

Q9:HTML5 有哪些方式可以实现离线存储?

A

  1. localStorage / sessionStorage:存储键值对数据
  2. IndexedDB:浏览器端的 NoSQL 数据库,可存储大量结构化数据
  3. Cache API(配合 Service Worker):缓存网络请求和响应,实现离线访问
  4. Application Cache(已废弃,被 Service Worker 取代)

现代 PWA(渐进式 Web 应用)主要使用 Service Worker + Cache API 实现离线功能。

Q10:如何实现浏览器跨标签页通信?

A:常见方案有:

  1. localStorage + storage 事件:一个标签页写入 localStorage,其他同源标签页通过 storage 事件监听到变化
  2. BroadcastChannel API:创建命名频道,同源标签页可以互相广播消息
  3. SharedWorker:多个标签页共享同一个 Worker,通过 Worker 中转消息
  4. WebSocket:通过服务器中转消息(可跨域)
  5. postMessage:如果标签页之间有 window.open 或 iframe 关系,可以用 postMessage 通信

其中最简单的方案是 localStorage + storage 事件,最强大的是 BroadcastChannel API