HTML
约 5374 字大约 18 分钟
HTML
HTML基础概念 🟢
1. DOCTYPE的作用
- 声明文档类型和DTD规范
- 决定浏览器的呈现模式(标准模式/混杂模式)
- HTML5的DOCTYPE写法:
<!DOCTYPE html>
标准模式和混杂模式的区别
- 标准模式:按W3C标准解析渲染页面
- 混杂模式:向后兼容的解析方式
- 主要区别:
- 盒模型的解析差异
- 图片元素垂直对齐方式
- 内联元素尺寸的解析差异
- 溢出处理方式
2. 字符编码
- UTF-8:万国码,支持多语言
- meta charset的设置:
<meta charset="UTF-8">
- 常见编码问题及解决方案:
- 乱码问题:确保页面编码与文件编码一致
- BOM头问题:使用无BOM的UTF-8编码
- 特殊字符处理:使用HTML实体
3. Meta标签完整指南
<!-- 基本meta标签 -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- SEO相关 -->
<meta name="description" content="网站描述,建议不超过150个字符">
<meta name="keywords" content="关键词1,关键词2">
<meta name="author" content="作者姓名">
<meta name="robots" content="index,follow">
<meta name="googlebot" content="index,follow">
<!-- 社交媒体优化 -->
<meta property="og:title" content="页面标题">
<meta property="og:description" content="页面描述">
<meta property="og:image" content="图片URL">
<meta property="og:url" content="页面URL">
<!-- 移动端相关 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="format-detection" content="telephone=no,email=no">
<!-- 缓存控制 -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
HTML5 新特性深入解析 🟢
1. 语义化标签的使用场景和注意事项
<header>
: 页面或区块的头部,每个区域可以有自己的header<nav>
: 导航链接区域,可以有多个nav<main>
: 主要内容,每个页面只能有一个<article>
: 独立的内容区域,如博客文章、新闻<section>
: 按主题分组的内容,通常含有标题<aside>
: 非主要内容,如广告、相关链接<footer>
: 页面或区块的底部信息<figure>/<figcaption>
: 图片及其标题的组合<time>
: 时间标记,利于机器理解<mark>
: 需要突出显示或引用的文本<details>/<summary>
: 可展开/折叠的内容区域
2. 多媒体标签的高级特性
音频 <audio>
高级配置
<audio controls
autoplay
loop
preload="auto"
controlsList="nodownload noplaybackrate"
crossorigin="anonymous"
muted>
<source src="audio.mp3" type="audio/mpeg">
<source src="audio.ogg" type="audio/ogg">
<track kind="captions" src="captions.vtt" srclang="zh" label="中文字幕">
<p>您的浏览器不支持音频播放。<a href="audio.mp3">下载音频</a></p>
</audio>
视频 <video>
高级配置
<video width="320"
height="240"
controls
poster="poster.jpg"
preload="metadata"
playsinline
webkit-playsinline
x5-video-player-type="h5"
x5-video-player-fullscreen="true">
<source src="video.mp4" type="video/mp4">
<source src="video.webm" type="video/webm">
<track kind="subtitles" src="subtitles.vtt" srclang="zh" label="中文字幕">
<track kind="descriptions" src="descriptions.vtt" srclang="zh" label="视频描述">
<p>的浏览器不支持视频播放。<a href="video.mp4">下载视频</a></p>
</video>
3. Canvas和SVG的深入对比
Canvas详细特性
- 基于像素的位图渲染
- 性能较好,适合复杂动画
- 不支持事件处理
- 分辨率依赖
- 文本渲染能力较弱
SVG详细特性
- 基于矢量的图形渲染
- DOM操作支持事件处理
- 可以通过CSS控制样式
- 适合大面积图形渲染
- 复杂度高会影响性能
使用场景对比
Canvas适用场景:
- 游戏开发
- 图片编辑
- 数据可视化
- 实时图像处理
SVG适用场景:
- 图标系统
- 地图应用
- 图表制作
- 动画效果
4. HTML5表单验证完整指南
内置验证属性
<form id="myForm" novalidate>
<!-- 文本输入 -->
<input type="text"
required
minlength="3"
maxlength="10"
pattern="[A-Za-z]+"
title="只能包含字母">
<!-- 数字输入 -->
<input type="number"
min="0"
max="100"
step="5"
required>
<!-- 日期时间 -->
<input type="date"
min="2024-01-01"
max="2024-12-31">
<!-- 文件上传 -->
<input type="file"
accept=".jpg,.png"
multiple>
<!-- 自定义验证 -->
<input type="text"
id="custom"
oninput="validateCustom(this)">
</form>
JavaScript表单验证
// 自定义验证示例
function validateCustom(input) {
if (input.value.length < 6) {
input.setCustomValidity('长度必须大于6位');
} else {
input.setCustomValidity('');
}
}
// 表单验证
const form = document.getElementById('myForm');
form.addEventListener('submit', function(event) {
if (!form.checkValidity()) {
event.preventDefault();
// 显示自定义错误信息
Array.from(form.elements).forEach(element => {
if (!element.validity.valid) {
showError(element, element.validationMessage);
}
});
}
});
HTML5 API 高级应用 🟡
1. 离线存储完整配置
CACHE MANIFEST
# 版本号:v1.0.0
# 更新日期:2024-01-01
# 需要缓存的文件
CACHE:
index.html
css/style.css
js/main.js
images/logo.png
fonts/custom.woff2
# 永远不缓存,需要网络
NETWORK:
*
api/*
analytics.js
# 离线替代文件
FALLBACK:
/ offline.html
images/ offline-image.png
2. 地理定位高级配置
const options = {
enableHighAccuracy: true, // 高精度
timeout: 5000, // 超时时间
maximumAge: 0 // 缓存时间
};
function success(pos) {
const crd = pos.coords;
console.log('位置信息:');
console.log(`纬度:${crd.latitude}`);
console.log(`经度:${crd.longitude}`);
console.log(`精确度:${crd.accuracy}米`);
if (crd.altitude) {
console.log(`海拔:${crd.altitude}米`);
}
}
function error(err) {
console.warn(`ERROR(${err.code}): ${err.message}`);
}
navigator.geolocation.getCurrentPosition(success, error, options);
3. 拖放API完整实现
<div draggable="true"
id="draggable"
ondragstart="handleDragStart(event)"
ondrag="handleDrag(event)"
ondragend="handleDragEnd(event)">
可拖拽元素
</div>
<div id="droppable"
ondragenter="handleDragEnter(event)"
ondragover="handleDragOver(event)"
ondragleave="handleDragLeave(event)"
ondrop="handleDrop(event)">
放置区域
</div>
// 拖拽元素相关事件
function handleDragStart(e) {
e.dataTransfer.setData('text/plain', e.target.id);
e.target.style.opacity = '0.4';
}
function handleDrag(e) {
// 拖拽过程中的处理
}
function handleDragEnd(e) {
e.target.style.opacity = '1';
}
// 放置区域相关事件
function handleDragEnter(e) {
e.preventDefault();
e.target.classList.add('drag-over');
}
function handleDragOver(e) {
e.preventDefault();
}
function handleDragLeave(e) {
e.target.classList.remove('drag-over');
}
function handleDrop(e) {
e.preventDefault();
const id = e.dataTransfer.getData('text/plain');
const draggable = document.getElementById(id);
e.target.appendChild(draggable);
e.target.classList.remove('drag-over');
}
4. Web Workers
// 主线程
const worker = new Worker('worker.js');
// 发送消息给Worker
worker.postMessage({
type: 'compute',
data: [1, 2, 3, 4]
});
// 接收Worker消息
worker.onmessage = function(e) {
console.log('计算结果:', e.data);
};
// 错误处理
worker.onerror = function(error) {
console.error('Worker错误:', error);
};
// worker.js
self.onmessage = function(e) {
if (e.data.type ``` 'compute') {
const result = e.data.data.reduce((a, b) => a + b, 0);
self.postMessage(result);
}
};
5. WebSocket详细使用
const ws = new WebSocket('ws://example.com/socket');
// 连接建立时触发
ws.onopen = function() {
console.log('连接已建立');
// 发送消息
ws.send(JSON.stringify({
type: 'subscribe',
channel: 'news'
}));
};
// 接收消息
ws.onmessage = function(evt) {
const message = JSON.parse(evt.data);
console.log('收到消息:', message);
};
// 错误处理
ws.onerror = function(error) {
console.error('WebSocket错误:', error);
};
// 连接关闭
ws.onclose = function() {
console.log('连接已关闭');
};
6. History API高级应用
// 添加新的历史记录
window.history.pushState(
{ page: 1 }, // 状态对象
'Title', // 标题(大多数浏览器忽略)
'/new-page' // URL
);
// 替换当前历史记录
window.history.replaceState(
{ page: 1 },
'Title',
'/replace-page'
);
// 监听popstate事件
window.addEventListener('popstate', function(event) {
if (event.state) {
console.log('当前页面:', event.state.page);
}
});
// 实现前端路由
class Router {
constructor(routes) {
this.routes = routes;
this.handleLocation = this.handleLocation.bind(this);
window.addEventListener('popstate', this.handleLocation);
window.addEventListener('load', this.handleLocation);
}
handleLocation() {
const path = window.location.pathname;
const route = this.routes[path] || this.routes[404];
route();
}
navigate(path) {
window.history.pushState({}, '', path);
this.handleLocation();
}
}
HTML5高级特性
1. Shadow DOM
<div id="host"></div>
<script>
// 创建Shadow DOM
const host = document.getElementById('host');
const shadow = host.attachShadow({mode: 'open'});
// 添加内容
shadow.innerHTML = `
<style>
.card {
padding: 10px;
border: 1px solid #ccc;
}
</style>
<div class="card">
<h2>Shadow DOM Content</h2>
<slot name="content"></slot>
</div>
`;
</script>
2. Custom Elements
// 定义自定义元素
class UserCard extends HTMLElement {
constructor() {
super();
// 创建Shadow DOM
const shadow = this.attachShadow({mode: 'open'});
// 添加样式和内容
shadow.innerHTML = `
<style>
.user-card {
display: flex;
align-items: center;
padding: 10px;
border: 1px solid #ccc;
}
img {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 10px;
}
</style>
<div class="user-card">
<img src="${this.getAttribute('avatar')}">
<div>
<h3>${this.getAttribute('name')}</h3>
<p>${this.getAttribute('email')}</p>
</div>
</div>
`;
}
}
// 注册自定义元素
customElements.define('user-card', UserCard);
3. Template和Slot
<!-- 模板定义 -->
<template id="user-template">
<style>
.user {
display: flex;
align-items: center;
}
</style>
<div class="user">
<img src="" alt="avatar">
<div class="user-info">
<slot name="username"></slot>
<slot name="email"></slot>
</div>
</div>
</template>
<!-- 使用模板 -->
<div id="user">
<h3 slot="username">John Doe</h3>
<p slot="email">john@example.com</p>
</div>
<script>
const template = document.getElementById('user-template');
const user = document.getElementById('user');
const clone = template.content.cloneNode(true);
user.appendChild(clone);
</script>
高级面试题
1. 渲染优化相关
Q1: 什么是关键渲染路径(Critical Rendering Path)?如何优化? A1:
- 关键渲染路径是浏览器将HTML、CSS和JavaScript转换为屏幕上的像素所经历的步骤
- 优化方法:
- 最小化关键资源数量
- 最小化关键字节数
- 最小化关键路径长度
- 优先加载关键资源
- 异步加载非关键资源
Q2: 如何优化首屏加载时间? A2:
- 服务端渲染(SSR)
- 路由懒加载
- 图片懒加载
- 资源预加载
- 合理的缓存策略
- 使用CDN
- Gzip压缩
- 代码分割
2. 可访问性(Accessibility)相关
Q1: 如何提高网站的可访问性? A1:
- 使用语义化标签
- 提供替代文本
- 确保键盘可访问
- 使用ARIA属性
- 提供足够的颜色对比度
- 支持屏幕阅读器
<!-- 可访问性示例 -->
<nav role="navigation" aria-label="主导航">
<ul>
<li><a href="#" aria-current="page">首页</a></li>
<li><a href="#" role="menuitem">关于</a></li>
</ul>
</nav>
<img src="logo.png" alt="公司标志" aria-label="XX公司Logo">
<button aria-label="关闭" aria-expanded="false">
<span class="icon-close"></span>
</button>
3. SEO优化相关
Q1: HTML中如何优化SEO? A1:
- 使用合适的标题层级
- 优化meta标签
- 使用语义化标签
- 提供有意义的alt文本
- 优化URL结构
- 使用规范的链接
- 提供sitemap.xml
- 实现结构化数据
<!-- SEO优化示例 -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>页面标题 - 网站名称</title>
<meta name="description" content="页面描述,150字以内">
<meta name="keywords" content="关键词1,关键词2">
<link rel="canonical" href="https://example.com/page">
<!-- 结构化数据 -->
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "Article",
"headline": "文章标题",
"author": {
"@type": "Person",
"name": "作者名"
},
"datePublished": "2024-01-01"
}
</script>
</head>
<body>
<header>
<h1>主标题</h1>
<nav>
<ul>
<li><a href="/">首页</a></li>
</ul>
</nav>
</header>
</body>
</html>
4. 性能监控
Q1: 如何监控页面性能? A1:
- 使用Performance API
- 监控关键指标:
- FCP (First Contentful Paint)
- LCP (Largest Contentful Paint)
- FID (First Input Delay)
- CLS (Cumulative Layout Shift)
- TTI (Time to Interactive)
// 性能监控示例
// 使用Performance API
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(`${entry.name}: ${entry.startTime}ms`);
}
});
observer.observe({
entryTypes: ['paint', 'largest-contentful-paint', 'first-input', 'layout-shift']
});
// 获取关键时间点
window.addEventListener('load', () => {
const timing = performance.timing;
console.log(`DNS查询时间: ${timing.domainLookupEnd - timing.domainLookupStart}ms`);
console.log(`TCP连接时间: ${timing.connectEnd - timing.connectStart}ms`);
console.log(`页面加载时间: ${timing.loadEventEnd - timing.navigationStart}ms`);
});
最佳实践
1. 响应式图片完整解决方案
<!-- 使用srcset和sizes -->
<img srcset="small.jpg 300w,
medium.jpg 600w,
large.jpg 900w"
sizes="(max-width: 320px) 280px,
(max-width: 640px) 580px,
800px"
src="fallback.jpg"
alt="响应式图片">
<!-- 使用picture元素 -->
<picture>
<source media="(min-width: 800px)" srcset="hero.jpg">
<source media="(min-width: 400px)" srcset="hero-medium.jpg">
<img src="hero-small.jpg" alt="响应式图片">
</picture>
2. 表单高级特性
<!-- 高级表单示例 -->
<form id="advanced-form" autocomplete="on">
<!-- 数据列表 -->
<input list="browsers" name="browser">
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
<option value="Safari">
</datalist>
<!-- 自定义验证 -->
<input type="text"
pattern="[A-Za-z]{3}"
title="请输入3个字母"
required>
<!-- 输出元素 -->
<output name="result" for="a b">0</output>
<!-- 进度条 -->
<progress value="70" max="100">70%</progress>
<!-- 度量器 -->
<meter value="0.6" min="0" max="1" low="0.3" high="0.7" optimum="0.5">60%</meter>
</form>
3. 性能优化最佳实践
- 资源加载优化:
<!-- 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="main.js" as="script">
<!-- 预加载字体 -->
<link rel="preload"
href="font.woff2"
as="font"
type="font/woff2"
crossorigin>
<!-- DNS预解析 -->
<link rel="dns-prefetch" href="//api.example.com">
<!-- 预连接 -->
<link rel="preconnect" href="https://api.example.com">
- 图片优化:
<!-- 响应式图片 -->
<picture>
<!-- WebP格式 -->
<source type="image/webp"
srcset="image.webp">
<!-- 不同分辨率 -->
<source media="(min-width: 800px)"
srcset="large.jpg">
<source media="(min-width: 400px)"
srcset="medium.jpg">
<!-- 默认图片 -->
<img src="small.jpg"
alt="响应式图片"
loading="lazy">
</picture>
- 脚本加载优化:
<!-- 异步加载非关键脚本 -->
<script src="analytics.js" async></script>
<!-- 延迟加载非关键脚本 -->
<script src="non-critical.js" defer></script>
<!-- 模块化脚本 -->
<script type="module" src="app.js"></script>
4. 可访问性最佳实践
- ARIA属性使用:
<!-- 导航菜单 -->
<nav role="navigation" aria-label="主导航">
<ul role="menubar">
<li role="menuitem">
<a href="#" aria-current="page">首页</a>
</li>
</ul>
</nav>
<!-- 模态对话框 -->
<div role="dialog"
aria-labelledby="dialogTitle"
aria-describedby="dialogDesc">
<h2 id="dialogTitle">标题</h2>
<p id="dialogDesc">描述内容</p>
</div>
<!-- 表单错误提示 -->
<input type="email"
aria-invalid="true"
aria-errormessage="emailError">
<span id="emailError" role="alert">
请输入有效的邮箱地址
</span>
HTML5高级特性补充
1. MutationObserver
用于监视DOM变化的接口
// 创建观察器
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type ``` 'childList') {
console.log('子节点变化');
} else if (mutation.type ``` 'attributes') {
console.log(`${mutation.attributeName}属性变化`);
}
});
});
// 配置观察选项
const config = {
attributes: true, // 监视属性变化
childList: true, // 监视子节点变化
subtree: true, // 监视所有后代节点
attributeOldValue: true // 记录属性的上一个值
};
// 开始观察
observer.observe(targetNode, config);
// 停止观察
observer.disconnect();
2. IntersectionObserver
用于监视元素进入或离开视口
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log('元素进入视口');
// 可以用于图片懒加载
entry.target.src = entry.target.dataset.src;
}
});
}, {
root: null, // 视口
rootMargin: '0px', // 视口边距
threshold: 0.5 // 可见比例阈值
});
// 开始观察
observer.observe(targetElement);
3. HTML5高级表单特性
自定义表单验证API
// 创建自定义验证器
class CustomValidation {
constructor(input) {
this.input = input;
this.validityState = input.validity;
}
checkValidity() {
const value = this.input.value;
if (value.length < 6) {
this.input.setCustomValidity('长度必须大于6位');
return false;
}
if (!/[A-Z]/.test(value)) {
this.input.setCustomValidity('必须包含大写字母');
return false;
}
this.input.setCustomValidity('');
return true;
}
}
// 使用示例
const input = document.querySelector('#password');
const validator = new CustomValidation(input);
input.addEventListener('input', () => {
validator.checkValidity();
});
表单数据的高级处理
// FormData高级用法
const form = document.querySelector('#myForm');
const formData = new FormData(form);
// 添加数据
formData.append('custom', 'value');
// 设置数据(会覆盖同名数据)
formData.set('field', 'new value');
// 删除数据
formData.delete('field');
// 获取所有数据
for (const [key, value] of formData.entries()) {
console.log(`${key}: ${value}`);
}
// 检查是否包含某个字段
console.log(formData.has('field'));
// 获取同名字段的所有值
const values = formData.getAll('field');
4. HTML5 Microdata
用于向网页添加语义化数据
<article itemscope itemtype="http://schema.org/Article">
<header>
<h1 itemprop="headline">文章标题</h1>
<p>
作者:<span itemprop="author">张三</span>
发布日期:<time itemprop="datePublished" datetime="2024-01-01">2024年1月1日</time>
</p>
</header>
<div itemprop="articleBody">
文章内容...
</div>
<footer>
<p>分类:<span itemprop="articleSection">技术</span></p>
</footer>
</article>
5. HTML5 Dialog对话框
<dialog id="myDialog">
<h2>对话框标题</h2>
<p>对话框内容...</p>
<button onclick="closeDialog()">关闭</button>
</dialog>
<button onclick="showDialog()">打开对话框</button>
<script>
const dialog = document.getElementById('myDialog');
function showDialog() {
// 模态对话框
dialog.showModal();
// 非模态对话框
// dialog.show();
}
function closeDialog() {
dialog.close();
}
// 监听对话框关闭事件
dialog.addEventListener('close', () => {
console.log('对话框已关闭');
});
</script>
6. HTML5 Picture元素的高级用法
<picture>
<!-- 艺术指导 -->
<source
media="(orientation: landscape)"
srcset="landscape.jpg">
<source
media="(orientation: portrait)"
srcset="portrait.jpg">
<!-- 分辨率切换 -->
<source
media="(min-width: 800px)"
srcset="large.jpg 1024w,
medium.jpg 640w"
sizes="(min-width: 1200px) 1024px,
(min-width: 800px) 640px">
<!-- 格式回退 -->
<source type="image/webp" srcset="image.webp">
<source type="image/jpeg" srcset="image.jpg">
<!-- 默认图片 -->
<img src="fallback.jpg" alt="响应式图片示例">
</picture>
7. HTML5 表单元素的高级特性
<!-- 日期和时间输入 -->
<input type="datetime-local"
min="2024-01-01T00:00"
max="2024-12-31T23:59">
<!-- 颜色选择器带透明度 -->
<input type="color"
value="#ff0000"
list="presetColors">
<datalist id="presetColors">
<option>#ff0000</option>
<option>#00ff00</option>
<option>#0000ff</option>
</datalist>
<!-- 范围滑块带刻度 -->
<input type="range"
min="0"
max="100"
step="10"
list="tickmarks">
<datalist id="tickmarks">
<option value="0">0%</option>
<option value="50">50%</option>
<option value="100">100%</option>
</datalist>
<!-- 带建议的搜索框 -->
<input type="search"
list="searchSuggestions"
autocomplete="off">
<datalist id="searchSuggestions">
<option value="搜索建议1">
<option value="搜索建议2">
</datalist>
更多面试重点
1. HTML5 API相关问题
Q1: 说说你对Service Worker的理解? A1:
- Service Worker是一个独立的线程,可以在后台运行
- 主要用于实现离线缓存、消息推送、后台同步等功能
- 必须在HTTPS环境下运行
- 生命周期包括:注册、安装、激活
- 可以拦截和处理网络请求
Q2: 浏览器存储方案的区别和使用场景? A2:
Cookie:
- 主要用于服务器识别用户
- 容量限制4KB
- 每次请求都会携带
- 可设置过期时间
LocalStorage:
- 永久存储
- 容量一般为5MB
- 不会随请求发送
- 同源策略限制
SessionStorage:
- 会话期间有效
- 容量一般为5MB
- 标签页隔离
- 同源策略限制
IndexedDB:
- 适合存储大量结构化数据
- 支持索引和事务
- 异步API
- 同源策略限制
2. HTML语义化相关问题
Q1: 为什么要使用语义化标签?使用div和span有什么区别? A1:
语义化的优势:
- 代码可读性更好
- 有利于SEO
- 便于屏幕阅读器解析
- 便于团队开发和维护
div和span的区别:
- div是块级元素,span是内联元素
- div用于布局,span用于文本
- 语义化程度较低,建议适当使用语义化标签
Q2: HTML5新标签的兼容性如何处理? A2:
- 使用特性检测:
if ('geolocation' in navigator) {
// 支持地理位置API
}
- 使用Polyfill:
<!--[if lt IE 9]>
<script src="html5shiv.js"></script>
<![endif]-->
- 使用现代构建工具:
- Babel转译
- PostHTML处理
- Modernizr检测
3. HTML性能优化问题
Q1: 如何优化HTML文档的加载性能? A1:
文档结构优化:
- 将CSS放在头部
- 将JS放在底部
- 使用async/defer加载脚本
- 避免重定向
资源优化:
- 使用CDN
- 开启Gzip压缩
- 图片懒加载
- 使用适当的图片格式
缓存策略:
- 合理设置Cache-Control
- 使用ETag
- 利用Service Worker缓存
预加载技术:
<!-- DNS预解析 -->
<link rel="dns-prefetch" href="//example.com">
<!-- 预加载 -->
<link rel="preload" href="style.css" as="style">
<!-- 预连接 -->
<link rel="preconnect" href="https://example.com">
<!-- 预渲染 -->
<link rel="prerender" href="next-page.html">
4. HTML5新特性的实践问题
Q1: 如何实现一个拖放上传文件的功能? A1:
<div id="dropZone"
class="drop-zone"
ondragover="handleDragOver(event)"
ondrop="handleDrop(event)">
拖放文件到这里
</div>
<script>
function handleDragOver(e) {
e.preventDefault();
e.stopPropagation();
e.dataTransfer.dropEffect = 'copy';
}
function handleDrop(e) {
e.preventDefault();
e.stopPropagation();
const files = Array.from(e.dataTransfer.files);
files.forEach(file => {
if (file.type.match('image.*')) {
uploadFile(file);
}
});
}
async function uploadFile(file) {
const formData = new FormData();
formData.append('file', file);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
const result = await response.json();
console.log('上传成功:', result);
} catch (error) {
console.error('上传失败:', error);
}
}
</script>
Q2: 如何使用HTML5 API实现离线应用? A2:
- 使用Service Worker:
// 注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW注册成功');
})
.catch(error => {
console.log('SW注册失败:', error);
});
}
// sw.js
const CACHE_NAME = 'v1';
const CACHE_URLS = [
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png'
];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(CACHE_URLS))
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
- 使用Application Cache(已废弃,仅供参考):
<html manifest="cache.manifest">
<!-- 页面内容 -->
</html>
5. HTML5语义化标签相关
Q1: HTML5语义化标签在SEO中的作用是什么? A1:
提升网页结构的清晰度:
- 搜索引擎更容易理解页面结构
- 更准确地提取关键信息
- 有助于确定内容的重要性
具体好处:
- 更好的可访问性
- 更好的移动端优化
- 更好的搜索引擎优化
- 更好的代码可维护性
Q2: 如何正确使用HTML5语义化标签? A2:
<!-- 正确的语义化结构示例 -->
<header>
<h1>网站名称</h1>
<nav>
<ul>
<li><a href="#home">首页</a></li>
<li><a href="#about">关于</a></li>
</ul>
</nav>
</header>
<main>
<article>
<header>
<h2>文章标题</h2>
<time datetime="2024-01-01">2024年1月1日</time>
</header>
<section>
<h3>第一部分</h3>
<p>内容...</p>
</section>
<section>
<h3>第二部分</h3>
<p>内容...</p>
</section>
<footer>
<p>作者:张三</p>
</footer>
</article>
<aside>
<h2>相关文章</h2>
<ul>
<li><a href="#">推荐文章1</a></li>
<li><a href="#">推荐文章2</a></li>
</ul>
</aside>
</main>
<footer>
<p>© 2024 版权信息</p>
</footer>
6. HTML5多媒体相关
Q1: 如何优化视频播放体验? A1:
- 视频加载优化:
<video preload="metadata">
<!-- 使用多个源,浏览器会选择第一个支持的格式 -->
<source src="video.webm" type="video/webm">
<source src="video.mp4" type="video/mp4">
<!-- 提供字幕 -->
<track kind="subtitles"
src="subtitles.vtt"
srclang="zh"
label="中文字幕">
</video>
- 性能优化:
- 使用视频预加载
- 使用视频封面图
- 延迟加载非首屏视频
- 根据网络状况调整清晰度
Q2: 音频和视频标签的区别和使用注意事项? A2:
- 主要区别:
- 视频标签支持封面图(poster属性)
- 视频标签支持画中画模式
- 音频标签更轻量级
- 共同特性:
- 都支持多源
- 都支持预加载
- 都支持控制栏
- 都支持自动播放(需要考虑浏览器策略)
7. HTML5表单验证相关
Q1: 如何实现复杂的表单验证? A1:
- 使用HTML5原生验证:
<form id="myForm" novalidate>
<!-- 密码强度验证 -->
<input type="password"
pattern="^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$"
title="密码至少8位,包含字母和数字"
required>
<!-- 自定义错误信息 -->
<input type="email"
oninvalid="this.setCustomValidity('请输入有效的邮箱地址')"
oninput="this.setCustomValidity('')"
required>
</form>
- 使用约束验证API:
const form = document.getElementById('myForm');
const password = form.querySelector('input[type="password"]');
password.addEventListener('input', function() {
if (this.validity.patternMismatch) {
this.setCustomValidity('密码必须包含字母和数字,且至少8位');
} else {
this.setCustomValidity('');
}
});
form.addEventListener('submit', function(event) {
if (!this.checkValidity()) {
event.preventDefault();
// 显示自定义错误信息
Array.from(this.elements).forEach(element => {
if (!element.validity.valid) {
showError(element);
}
});
}
});
8. HTML5存储相关
Q1: 如何选择合适的HTML5存储方案? A1:
- 数据量较小,需要持久存储:
// localStorage
class Storage {
static set(key, value, expires = null) {
const item = {
value,
expires: expires ? new Date().getTime() + expires * 1000 : null
};
localStorage.setItem(key, JSON.stringify(item));
}
static get(key) {
const item = JSON.parse(localStorage.getItem(key));
if (!item) return null;
if (item.expires && item.expires < new Date().getTime()) {
localStorage.removeItem(key);
return null;
}
return item.value;
}
}
- 大量结构化数据:
// IndexedDB
class DB {
static async open(name, version) {
return new Promise((resolve, reject) => {
const request = indexedDB.open(name, version);
request.onerror = () => reject(request.error);
request.onsuccess = () => resolve(request.result);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// 创建存储对象
if (!db.objectStoreNames.contains('users')) {
db.createObjectStore('users', { keyPath: 'id' });
}
};
});
}
}
9. HTML5 API实践
Q1: 如何使用HTML5 API实现文件上传预览? A1:
<input type="file"
accept="image/*"
multiple
onchange="handleFiles(this.files)">
<div id="preview"></div>
<script>
function handleFiles(files) {
const preview = document.getElementById('preview');
preview.innerHTML = '';
Array.from(files).forEach(file => {
if (!file.type.startsWith('image/')) return;
const reader = new FileReader();
reader.onload = (e) => {
const img = document.createElement('img');
img.src = e.target.result;
img.height = 100;
preview.appendChild(img);
};
reader.readAsDataURL(file);
});
}
</script>
Q2: 如何实现离线应用功能? A2:
- 使用Service Worker:
// 注册Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker
.register('/sw.js', { scope: '/' })
.then(registration => {
console.log('SW注册成功,作用域:', registration.scope);
})
.catch(error => {
console.error('SW注册失败:', error);
});
}
// sw.js
const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png'
];
// 安装阶段缓存资源
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME)
.then(cache => cache.addAll(urlsToCache))
);
});
// 拦截请求并返回缓存
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => {
if (response) {
return response;
}
return fetch(event.request);
})
);
});