HTML
一、HTML 基础概念
1. 什么是 HTML?它的基本结构是什么?
定义: HTML(HyperText Markup Language,超文本标记语言)是一种用于创建网页的标准标记语言。它通过一组预定义的标签来描述网页的内容结构,是 Web 开发的基础技术之一。
原理:
- HTML 不是编程语言,而是标记语言
- 使用标签(Tag)来标注内容的语义和结构
- 浏览器解析 HTML 文档,构建 DOM(文档对象模型)树,然后渲染页面
基本结构:
html
<!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>
<h1>主标题</h1>
<p>这是一个段落。</p>
</body>
</html>
结构说明:
<!DOCTYPE html>:声明文档类型为 HTML5<html>:根元素,包含整个页面内容<head>:元数据区域,包含字符集、视口设置、标题等<body>:可见内容区域,包含所有页面元素
常见误区:
- 混淆 HTML 与 CSS、JavaScript 的职责:HTML 负责结构,CSS 负责样式,JavaScript 负责行为
- 忽略
lang属性:应设置正确的语言代码,有助于屏幕阅读器和 SEO <head>和<body>不能嵌套错误
2. HTML 文档的标准组成部分
标准组成部分:
- 文档类型声明(DOCTYPE):告知浏览器使用哪个 HTML 版本解析
- 根元素(html):整个文档的容器
- 头部区域 (head):
- 字符编码声明(charset)
- 视口设置(viewport)
- 页面标题(title)
- 元数据(meta)
- 外部资源链接(link、script)
- 主体区域(body):用户可见的所有内容
示例:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<!-- 字符编码 -->
<meta charset="UTF-8">
<!-- 视口设置 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- SEO 相关 -->
<meta name="description" content="页面描述">
<meta name="keywords" content="关键词1, 关键词2">
<title>网页标题</title>
<!-- 外部资源 -->
<link rel="stylesheet" href="style.css">
<link rel="icon" href="favicon.ico">
</head>
<body>
<header>页眉</header>
<main>主要内容</main>
<footer>页脚</footer>
</body>
</html>
3. <!DOCTYPE> 的作用及 HTML5 意义
定义 : <!DOCTYPE> 是文档类型声明(Document Type Declaration),位于 HTML 文档的第一行,告知浏览器使用哪种 HTML 规范来解析页面。
作用:
- 触发浏览器的标准模式 (Standards Mode),而非怪异模式(Quirks Mode)
- 确保浏览器按照 W3C 标准渲染页面
- 避免不同浏览器之间的渲染差异
HTML4 与 HTML5 的对比:
| 特性 | HTML 4.01 | HTML5 |
|---|---|---|
| 声明语法 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> |
<!DOCTYPE html> |
| 复杂度 | 冗长,基于 SGML | 简洁,不再基于 SGML |
| 大小写 | 不区分大小写 | 不区分大小写 |
| 作用 | 指向 DTD 文档 | 仅触发标准模式 |
HTML5 DOCTYPE 的意义:
- 极简设计 :只需
<!DOCTYPE html>,易于记忆和编写 - 向后兼容:所有现代浏览器都支持
- 不再依赖 DTD:HTML5 不再基于 SGML,不需要 DTD 引用
- 触发标准模式:确保一致的渲染行为
常见误区:
- 认为 DOCTYPE 是 HTML 标签:它不是标签,是声明
- 省略 DOCTYPE 会导致怪异模式:在怪异模式下,浏览器会模拟旧版行为,导致布局异常
怪异模式示例:
html
<!-- 没有 DOCTYPE,触发怪异模式 -->
<html>
<head><title>怪异模式</title></head>
<body>
<div style="width: 50%; margin: 0 auto;">
<!-- 在怪异模式下,盒模型计算方式不同 -->
</div>
</body>
</html>
二、HTML5 新特性
4. HTML5 主要新特性有哪些?
定义: HTML5 是 HTML 的第五个重大版本,于 2014 年成为 W3C 推荐标准。它引入了大量新特性,旨在改善 Web 应用开发体验。
主要新特性分类:
(1)语义化标签
html
<header>、<nav>、<main>、<section>、<article>、
<aside>、<footer>、<figure>、<figcaption>、
<time>、<mark>、<details>、<summary>
(2)多媒体支持
html
<!-- 原生音频 -->
<audio controls>
<source src="audio.mp3" type="audio/mpeg">
</audio>
<!-- 原生视频 -->
<video width="640" height="480" controls>
<source src="video.mp4" type="video/mp4">
</video>
(3)Canvas 绘图
html
<canvas id="myCanvas" width="200" height="100"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FF0000';
ctx.fillRect(0, 0, 150, 75);
</script>
(4)表单增强
html
<!-- 新输入类型 -->
<input type="email" required>
<input type="url" placeholder="请输入网址">
<input type="date" min="2024-01-01">
<input type="number" min="0" max="100" step="5">
<input type="range" min="0" max="100">
<input type="search" placeholder="搜索...">
<input type="tel" pattern="[0-9]{11}">
<!-- 新属性 -->
<input type="text" placeholder="提示文字" autofocus>
<input type="text" autocomplete="on">
<input type="text" form="myForm">
<!-- 新元素 -->
<datalist id="browsers">
<option value="Chrome">
<option value="Firefox">
</datalist>
<input list="browsers" name="browser">
(5)Web Storage
javascript
// localStorage(持久化)
localStorage.setItem('key', 'value');
localStorage.getItem('key');
// sessionStorage(会话级)
sessionStorage.setItem('temp', 'data');
sessionStorage.getItem('temp');
(6)Web Workers
javascript
// 主线程
const worker = new Worker('worker.js');
worker.postMessage('start');
worker.onmessage = (e) => console.log(e.data);
// worker.js
onmessage = (e) => {
// 执行耗时操作
postMessage('done');
};
(7)WebSocket
javascript
const ws = new WebSocket('ws://localhost:8080');
ws.onopen = () => ws.send('Hello');
ws.onmessage = (e) => console.log(e.data);
(8)拖放 API
html
<div draggable="true" ondragstart="drag(event)">可拖拽元素</div>
<div ondrop="drop(event)" ondragover="allowDrop(event)">放置区域</div>
(9)地理位置 API
javascript
navigator.geolocation.getCurrentPosition(
(pos) => console.log(pos.coords.latitude, pos.coords.longitude)
);
(10)新增属性
contenteditable:使元素可编辑data-*:自定义数据属性hidden:隐藏元素download:链接下载属性
浏览器兼容处理策略:
html
<!-- 1. 条件注释(IE 专用) -->
<!--[if lt IE 9]>
<script src="html5shiv.js"></script>
<![endif]-->
<!-- 2. JavaScript 特性检测 -->
<script>
if (!('placeholder' in document.createElement('input'))) {
// 降级方案:使用 polyfill
}
</script>
<!-- 3. CSS 渐进增强 -->
<input type="email" required>
<style>
input:valid { border-color: green; }
input:invalid { border-color: red; }
</style>
<!-- 4. Modernizr 库 -->
<script src="modernizr.js"></script>
<script>
if (Modernizr.canvas) {
// 使用 Canvas
} else {
// 降级方案
}
</script>
三、HTML 语义化
5. 对 HTML 语义化的理解
定义: HTML 语义化是指使用恰当的 HTML 标签来表达内容的含义和结构,而不仅仅是为了视觉效果。即"用正确的标签做正确的事"。
原理:
- 每个 HTML 标签都有其特定的语义含义
- 选择标签时应考虑内容"是什么",而不是"长什么样"
- 语义化标签让机器(搜索引擎、屏幕阅读器等)能理解内容结构
语义化示例对比:
html
<!-- 非语义化写法 -->
<div class="header">
<div class="nav">
<div class="logo">Logo</div>
<div class="menu">菜单</div>
</div>
</div>
<div class="main-content">
<div class="article">
<div class="title">文章标题</div>
<div class="content">文章内容</div>
</div>
</div>
<div class="footer">页脚</div>
<!-- 语义化写法 -->
<header>
<nav>
<div class="logo">Logo</div>
<ul>
<li><a href="/">首页</a></li>
<li><a href="/about">关于</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>文章标题</h1>
<p>文章内容</p>
</article>
</main>
<footer>页脚</footer>
6. HTML 语义化的核心价值
价值维度:
| 价值维度 | 说明 | 受益方 |
|---|---|---|
| SEO 优化 | 搜索引擎能更好地理解页面结构,提高排名 | 网站运营者 |
| 可访问性 | 屏幕阅读器能正确解读内容,帮助残障用户 | 残障用户 |
| 代码可读性 | 开发者能更快理解页面结构,便于维护 | 开发团队 |
| 设备兼容 | 不同设备(手机、手表等)能更好地解析内容 | 终端用户 |
| 样式维护 | 减少 class 命名,CSS 选择器更简洁 | 前端开发者 |
具体场景:
html
<!-- 场景1:文章页面 -->
<article>
<header>
<h1>HTML5 语义化详解</h1>
<time datetime="2024-03-15">2024年3月15日</time>
<p>作者:张三</p>
</header>
<section>
<h2>什么是语义化</h2>
<p>语义化是...</p>
</section>
<section>
<h2>语义化的好处</h2>
<p>好处包括...</p>
</section>
<footer>
<p>版权声明:...</p>
</footer>
</article>
<!-- 场景2:侧边栏 -->
<aside>
<h3>相关文章</h3>
<ul>
<li><a href="#">文章1</a></li>
<li><a href="#">文章2</a></li>
</ul>
</aside>
<!-- 场景3:图表 -->
<figure>
<img src="chart.png" alt="2024年第一季度销售数据图表">
<figcaption>图1:2024年第一季度销售数据</figcaption>
</figure>
7. HTML5 新增的语义化标签及使用场景
常用语义化标签一览:
| 标签 | 含义 | 使用场景 | 数量限制 |
|---|---|---|---|
<header> |
页眉/头部 | 页面或区域的头部,可包含 logo、导航等 | 每区域1个 |
<nav> |
导航 | 主要导航链接组 | 多个 |
<main> |
主内容 | 页面核心内容,每个页面唯一 | 1个 |
<section> |
区块 | 具有主题相关内容分组 | 多个 |
<article> |
文章 | 独立完整的内容块(文章、评论等) | 多个 |
<aside> |
侧边栏 | 与主内容相关但独立的内容 | 多个 |
<footer> |
页脚 | 页面或区域的底部信息 | 每区域1个 |
<figure> |
媒体容器 | 图片、代码、图表等 | 多个 |
<figcaption> |
媒体标题 | <figure> 的标题说明 |
每个 figure 最多1个 |
<time> |
时间 | 日期、时间 | 多个 |
<mark> |
高亮 | 需要标记的文字 | 多个 |
<details> |
折叠内容 | 可展开/收起的内容 | 多个 |
<summary> |
折叠标题 | <details> 的可见标题 |
每个 details 1个 |
使用示例:
html
<!-- details/summary 折叠面板 -->
<details>
<summary>点击查看详情</summary>
<p>这里是隐藏的详细内容。</p>
</details>
<!-- mark 高亮文本 -->
<p>搜索结果显示:这是一段包含<mark>关键词</mark>的文本。</p>
<!-- time 时间标记 -->
<time datetime="2024-03-15T10:30:00+08:00">2024年3月15日 上午10:30</time>
<!-- figure + figcaption 图文组合 -->
<figure>
<pre><code>
console.log('Hello World');
</code></pre>
<figcaption>代码示例1</figcaption>
</figure>
常见误区:
<section>不是<div>的替代品:只有当内容有明确主题时才使用<section><article>可以嵌套:文章内的评论也是独立的<article><header>和<footer>可在每个区块中使用,不限于页面级别
四、HTML 基础元素分类
8. 元素分类区别(行内元素、块级元素、空元素)
定义:
| 类型 | 定义 | 特点 |
|---|---|---|
| 块级元素 | 独占一行的元素 | 默认宽度100%,可设置宽高,前后有换行 |
| 行内元素 | 不独占一行的元素 | 宽高由内容决定,设置宽高无效,不换行 |
| 空元素 | 没有内容的自闭合元素 | 没有结束标签,如 <br>、<img> |
行内元素、块级元素及空元素的常见标签:
块级元素(Block-level Elements)
html
<div> <!-- 通用容器 -->
<p> <!-- 段落 -->
<h1>~<h6> <!-- 标题 -->
<ul>、<ol>、<li> <!-- 列表 -->
<table> <!-- 表格 -->
<form> <!-- 表单 -->
<header> <!-- 页眉 -->
<footer> <!-- 页脚 -->
<section> <!-- 区块 -->
<article> <!-- 文章 -->
<aside> <!-- 侧边栏 -->
<nav> <!-- 导航 -->
<blockquote> <!-- 块引用 -->
<hr> <!-- 水平线 -->
<pre> <!-- 预格式化文本 -->
行内元素(Inline Elements)
html
<span> <!-- 通用容器 -->
<a> <!-- 链接 -->
<strong> <!-- 强调(重要) -->
<em> <!-- 强调(重音) -->
<b> <!-- 粗体 -->
<i> <!-- 斜体 -->
<img> <!-- 图片 -->
<br> <!-- 换行 -->
<input> <!-- 输入框 -->
<label> <!-- 标签 -->
<code> <!-- 代码 -->
<abbr> <!-- 缩写 -->
<cite> <!-- 引用标题 -->
空元素(Void Elements)
html
<br> <!-- 换行 -->
<hr> <!-- 水平线 -->
<img> <!-- 图片 -->
<input> <!-- 输入框 -->
<link> <!-- 外部资源链接 -->
<meta> <!-- 元数据 -->
<area> <!-- 图像映射区域 -->
<base> <!-- 基准URL -->
<col> <!-- 表格列 -->
<embed> <!-- 外部内容 -->
<param> <!-- 对象参数 -->
<source> <!-- 媒体资源 -->
<track> <!-- 媒体字幕 -->
<wbr> <!-- 换行机会 -->
对比表格:
| 特性 | 块级元素 | 行内元素 |
|---|---|---|
| 独占一行 | 是 | 否 |
| 可设置宽度/高度 | 是 | 否(通过 content 决定) |
| 可设置 margin/padding | 四边有效 | 左右有效,上下不影响布局 |
| 默认宽度 | 父元素100% | 内容宽度 |
| 可包含子元素 | 可包含块级和行内元素 | 一般只包含行内元素 |
| display 值 | block | inline |
CSS 转换示例:
css
/* 块级转行内 */
a {
display: block; /* 让链接变成块级,可设置宽高 */
width: 200px;
height: 50px;
}
/* 行内块元素 */
span {
display: inline-block; /* 保留行内特性,但可设置宽高 */
width: 100px;
height: 100px;
}
五、HTML 全局属性
9. HTML 全局属性有哪些?
定义: 全局属性是所有 HTML 元素都可以使用的公共属性。
常用全局属性一览表:
| 属性 | 说明 | 示例 |
|---|---|---|
id |
元素唯一标识符 | <div id="main"> |
class |
元素的类名(可多个) | <div class="box active"> |
style |
内联 CSS 样式 | <div style="color: red;"> |
title |
元素额外信息(鼠标悬停提示) | <abbr title="HyperText Markup Language">HTML</abbr> |
lang |
元素内容语言 | <p lang="zh-CN"> |
hidden |
隐藏元素(布尔属性) | <div hidden> |
tabindex |
Tab 键导航顺序 | <button tabindex="1"> |
accesskey |
键盘快捷键 | <button accesskey="s">保存</button> |
contenteditable |
使元素可编辑 | <div contenteditable="true"> |
draggable |
元素可拖拽 | <div draggable="true"> |
data-* |
自定义数据属性 | <div data-user-id="123"> |
dir |
文本方向 | <p dir="rtl"> |
spellcheck |
拼写检查 | <textarea spellcheck="true"> |
translate |
是否翻译 | <p translate="no"> |
slot |
Web Components 插槽 | <div slot="header"> |
重点属性示例:
html
<!-- contenteditable 可编辑内容 -->
<div contenteditable="true">
这段文字可以直接编辑
</div>
<!-- data-* 自定义数据 -->
<div
data-user-id="123"
data-user-name="张三"
data-role="admin"
>用户信息</div>
<script>
const el = document.querySelector('[data-user-id]');
console.log(el.dataset.userId); // "123"
console.log(el.dataset.userName); // "张三"
</script>
<!-- hidden 隐藏元素 -->
<div hidden>用户看不到这段内容</div>
<!-- 等价于 style="display: none;" -->
<!-- tabindex 控制 Tab 顺序 -->
<a href="/" tabindex="1">首页</a>
<a href="/about" tabindex="2">关于</a>
<a href="/contact" tabindex="3">联系</a>
六、src 和 href 区别
10. src 和 href 区别是什么?
定义:
src(source):表示资源引入,浏览器会暂停当前文档处理,先加载并处理该资源href(hypertext reference):表示超链接引用,浏览器会并行加载资源,不暂停当前文档
对比表格:
| 特性 | src | href |
|---|---|---|
| 全称 | source | hypertext reference |
| 语义 | 引入资源,替换当前元素内容 | 引用资源,建立链接关系 |
| 加载行为 | 暂停文档解析,加载并执行资源 | 并行加载,不阻塞文档解析 |
| 使用场景 | 替换型资源 | 关联型资源 |
| 常用元素 | <script>、<img>、<iframe>、<video> |
<link>、<a> |
示例说明:
html
<!-- src:引入脚本,会阻塞页面解析 -->
<script src="app.js"></script>
<!-- 优化:添加 defer 或 async -->
<script src="app.js" defer></script>
<!-- src:引入图片,替换 img 元素内容 -->
<img src="photo.jpg" alt="照片">
<!-- href:引用样式表,并行加载 -->
<link rel="stylesheet" href="style.css">
<!-- href:超链接 -->
<a href="https://example.com">访问网站</a>
选择策略:
- 需要加载并执行 资源时使用
src(脚本、图片、媒体、框架) - 需要建立链接关系 时使用
href(样式表、锚点链接)
七、strong vs em
11. strong 与 em 的区别是什么?
定义:
| 属性 | <strong> |
<em> |
|---|---|---|
| 全称 | strong importance | emphasis |
| 语义 | 重要性强,内容重要性更高 | 强调,重音强调 |
| 默认样式 | 粗体 | 斜体 |
| 屏幕阅读器 | 语气加重 | 重音读出 |
对比示例:
html
<!-- strong:表示内容重要性 -->
<p>警告:<strong>请勿在设备运行时打开外壳</strong></p>
<!-- em:表示语气强调 -->
<p>我<strong>真的</strong>很喜欢这个设计</p>
<!-- 改变 em 的位置可改变句子含义 -->
<p><em>你</em>今天要去吗?</p> <!-- 强调"你" -->
<p>你<em>今天</em>要去吗?</p> <!-- 强调"今天" -->
<p>你今天<em>要</em>去吗?</p> <!-- 强调"要" -->
<!-- 语义化对比 -->
<!-- 正确:使用 strong 表示警告 -->
<strong>重要通知</strong>
<!-- 错误:仅为了粗体效果 -->
<p style="font-weight: bold">标题</p> <!-- 应使用 <h1>-<h6> -->
常见误区:
<b>和<strong>:<b>只是视觉粗体,无语义;<strong>表示内容重要性<i>和<em>:<i>只是视觉斜体,无语义;em表示语气强调- HTML5 中
<b>、<i>仍有用途:<b>用于关键字、产品名;<i>用于术语、外语
八、img 的 alt 和 title 区别
12. img 的 alt 与 title 属性区别
定义:
| 属性 | alt | title |
|---|---|---|
| 全称 | alternative text | title |
| 语义 | 替代文本,图片无法显示时的替代内容 | 额外信息,鼠标悬停时显示 |
| 显示时机 | 图片加载失败、屏幕阅读器读取 | 鼠标悬停在图片上 |
| 必要性 | 推荐所有图片都添加 | 可选 |
| SEO 影响 | 直接影响 | 影响较小 |
| 可访问性 | 对无障碍访问至关重要 | 辅助信息 |
示例说明:
html
<!-- 正确用法 -->
<img
src="product.jpg"
alt="红色运动鞋,侧面视角,白色鞋底"
title="点击查看产品详情"
>
<!-- alt 的场景 -->
<!-- 1. 图片加载失败时显示 alt 文本 -->
<!-- 2. 屏幕阅读器朗读 alt 文本 -->
<!-- 3. 搜索引擎根据 alt 理解图片内容 -->
<!-- 装饰性图片:alt 留空 -->
<img src="decorative-line.png" alt="">
<!-- 屏幕阅读器会跳过装饰性图片 -->
选择策略:
- 必须加 alt :所有
<img>都应该有 alt 属性 - 内容图片:alt 应描述图片内容
- 功能图片:alt 应描述功能(如按钮图片写"提交"而非"绿色按钮")
- 装饰图片 :alt 留空(
alt=""),让屏幕阅读器跳过 - title:补充额外信息,但非必要
九、表单元素
13. HTML 表单元素类型有哪些?
定义 : 表单元素用于收集用户输入,通过 <form> 元素包裹,包含多种输入类型。
表单控件类型一览表:
html
<!-- 基础输入类型 -->
<input type="text"> <!-- 文本输入 -->
<input type="password"> <!-- 密码输入 -->
<input type="number"> <!-- 数字输入 -->
<input type="email"> <!-- 邮箱输入 -->
<input type="url"> <!-- URL输入 -->
<input type="tel"> <!-- 电话号码输入 -->
<input type="search"> <!-- 搜索框 -->
<input type="date"> <!-- 日期选择器 -->
<input type="time"> <!-- 时间选择器 -->
<input type="month"> <!-- 月份选择器 -->
<input type="week"> <!-- 周选择器 -->
<input type="datetime-local"><!-- 本地日期时间 -->
<input type="color"> <!-- 颜色选择器 -->
<input type="range"> <!-- 滑块 -->
<input type="file"> <!-- 文件上传 -->
<input type="checkbox"> <!-- 复选框 -->
<input type="radio"> <!-- 单选框 -->
<!-- 按钮类型 -->
<input type="submit"> <!-- 提交按钮 -->
<input type="reset"> <!-- 重置按钮 -->
<input type="button"> <!-- 普通按钮 -->
<button type="submit">提交</button>
<!-- 其他表单元素 -->
<select> <!-- 下拉选择 -->
<option>选项1</option>
<option>选项2</option>
</select>
<textarea>多行文本</textarea> <!-- 多行文本 -->
<label>标签</label> <!-- 输入标签 -->
<fieldset> <!-- 表单分组 -->
<legend>分组标题</legend>
<input type="text">
</fieldset>
<datalist id="list"> <!-- 预定义选项 -->
<option value="选项1">
</datalist>
<input list="list">
<output>结果</output> <!-- 计算结果输出 -->
<progress value="50" max="100">进度条</progress>
<meter value="0.6">计量器</meter>
表单属性:
html
<form action="/submit" method="POST" enctype="multipart/form-data">
<!-- 常用输入属性 -->
<input
type="text"
name="username"
value="默认值"
placeholder="请输入用户名"
required <!-- 必填 -->
maxlength="20" <!-- 最大长度 -->
minlength="2" <!-- 最小长度 -->
pattern="[a-z]+" <!-- 正则验证 -->
readonly <!-- 只读 -->
disabled <!-- 禁用 -->
autofocus <!-- 自动聚焦 -->
autocomplete="on" <!-- 自动补全 -->
>
</form>
14. HTML5 新增的表单控件类型有哪些?
HTML5 新增输入类型:
| 类型 | 说明 | 示例 | 适用场景 |
|---|---|---|---|
email |
邮箱验证 | <input type="email"> |
邮箱输入,移动端弹出邮箱键盘 |
url |
URL验证 | <input type="url"> |
网址输入 |
tel |
电话号码 | <input type="tel"> |
手机号输入,支持 pattern 验证 |
number |
数字输入 | <input type="number" min="0" max="100"> |
数值输入,带增减按钮 |
range |
滑块 | <input type="range" min="0" max="100"> |
音量、亮度等范围选择 |
date |
日期选择器 | <input type="date"> |
生日、预约日期 |
time |
时间选择器 | <input type="time"> |
时间选择 |
datetime-local |
本地日期时间 | <input type="datetime-local"> |
会议时间等 |
month |
月份选择器 | <input type="month"> |
信用卡有效期 |
week |
周选择器 | <input type="week"> |
周计划 |
color |
颜色选择器 | <input type="color"> |
颜色选取 |
search |
搜索框 | <input type="search"> |
搜索输入 |
HTML5 新增表单属性:
| 属性 | 说明 | 示例 |
|---|---|---|
placeholder |
输入提示 | placeholder="请输入邮箱" |
required |
必填验证 | required |
autofocus |
自动聚焦 | autofocus |
autocomplete |
自动补全 | autocomplete="on" |
pattern |
正则验证 | pattern="[0-9]{11}" |
min/max |
最小/最大值 | min="1" max="100" |
step |
步进值 | step="5" |
multiple |
多值选择 | multiple |
form |
关联表单 | form="myForm" |
novalidate |
禁用验证 | <form novalidate> |
HTML5 新增表单元素:
html
<!-- datalist:带建议的下拉输入 -->
<label for="browser">选择浏览器:</label>
<input list="browsers" id="browser" name="browser">
<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="0"> +
<input type="number" id="b" value="0"> =
<output name="result" for="a b">0</output>
</form>
<!-- progress:进度条 -->
<progress id="uploadProgress" value="30" max="100">30%</progress>
<!-- meter:计量器 -->
<meter value="0.7" min="0" max="1" low="0.3" high="0.8" optimum="0.9">70%</meter>
15. 单选框(radio)实现分组需满足的属性条件
分组条件:
- 同一组的单选框必须具有相同的
name属性值 - 每个单选框应有不同的
value属性值
示例说明:
html
<!-- 性别选择组(name相同) -->
<fieldset>
<legend>性别</legend>
<label>
<input type="radio" name="gender" value="male"> 男
</label>
<label>
<input type="radio" name="gender" value="female"> 女
</label>
<label>
<input type="radio" name="gender" value="other"> 其他
</label>
</fieldset>
<!-- 学历选择组(name相同但不同于性别组) -->
<fieldset>
<legend>学历</legend>
<label>
<input type="radio" name="education" value="highschool"> 高中
</label>
<label>
<input type="radio" name="education" value="bachelor"> 本科
</label>
<label>
<input type="radio" name="education" value="master"> 硕士
</label>
</fieldset>
关键点:
name相同 → 同组(只能选一个)name不同 → 不同组(可分别选择)- 建议使用
<label>包裹或关联,提升可访问性
十、SEO 优化
16. 从 SEO 角度提出 HTML 书写注意事项
定义: SEO(Search Engine Optimization,搜索引擎优化)是通过优化网页结构和内容,提高搜索引擎排名的技术。
HTML 层面的 SEO 优化注意事项:
(1)语义化标签使用
html
<!-- 正确使用语义化标签 -->
<header>
<nav>
<a href="/">首页</a>
</nav>
</header>
<main>
<article>
<h1>文章主标题(每页唯一)</h1>
<section>
<h2>小节标题</h2>
<h3>子小节标题</h3>
</section>
</article>
</main>
<footer>页脚</footer>
(2)合理的标题层级
html
<!-- 正确:层级递进 -->
<h1>网站名称</h1>
<h2>栏目名称</h2>
<h3>文章标题</h3>
<!-- 错误:跳级使用 -->
<h1>网站名称</h1>
<h3>跳过h2直接h3</h3> <!-- 不利于SEO -->
(3)Meta 标签优化
html
<head>
<!-- 页面标题(50-60字符) -->
<title>页面标题 - 品牌名称</title>
<!-- 页面描述(150-160字符) -->
<meta name="description" content="准确的页面描述,包含关键词">
<!-- 关键词(部分搜索引擎仍参考) -->
<meta name="keywords" content="关键词1, 关键词2, 关键词3">
<!-- 规范URL(避免重复内容) -->
<link rel="canonical" href="https://example.com/page">
<!-- Open Graph(社交媒体分享优化) -->
<meta property="og:title" content="分享标题">
<meta property="og:description" content="分享描述">
<meta property="og:image" content="分享图片">
<!-- robots 控制 -->
<meta name="robots" content="index, follow">
</head>
(4)图片优化
html
<!-- 必须添加 alt 属性 -->
<img src="product.jpg" alt="产品名称 - 红色运动鞋">
<!-- 使用 figure 包裹重要图片 -->
<figure>
<img src="chart.png" alt="2024年Q1销售增长图表">
<figcaption>2024年第一季度销售数据</figcaption>
</figure>
(5)结构化数据(Schema.org)
html
<!-- 使用 JSON-LD 格式 -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "文章标题",
"author": {
"@type": "Person",
"name": "作者名"
},
"datePublished": "2024-03-15"
}
</script>
(6)链接优化
html
<!-- 有意义的链接文本 -->
<a href="/about">了解我们的团队</a>
<!-- 而不是 -->
<a href="/about">点击这里</a>
<!-- 外部链接添加 rel 属性 -->
<a href="https://example.com" rel="noopener noreferrer">外部链接</a>
(7)页面加载速度优化
html
<!-- 预加载关键资源 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="font.woff2" as="font" crossorigin>
<!-- 延迟加载非关键资源 -->
<script src="analytics.js" defer></script>
<!-- 图片懒加载 -->
<img src="placeholder.jpg" data-src="real.jpg" loading="lazy" alt="图片">
17. SEO 优化方法有哪些?
多维度 SEO 优化策略:
| 维度 | 优化方法 | 具体实现 |
|---|---|---|
| HTML结构 | 语义化标签、标题层级、Meta标签 | 使用 <h1>-<h6>、<meta description> |
| 内容质量 | 原创内容、关键词密度 | 内容相关、自然关键词分布 |
| 页面速度 | 资源压缩、懒加载、缓存 | 图片压缩、CDN、HTTP/2 |
| 移动端适配 | 响应式设计、视口设置 | <meta viewport>、媒体查询 |
| 链接结构 | 内部链接、外部链接质量 | 合理的锚文本、高质量外链 |
| 结构化数据 | Schema.org、JSON-LD | 富媒体摘要显示 |
| 无障碍访问 | ARIA、alt属性 | 提升可访问性评分 |
十一、响应式设计与移动端适配
18. HTML 层面的响应式实现方法有哪些?
响应式设计原理: 响应式设计(Responsive Web Design)使网页能够根据不同设备的屏幕尺寸自动调整布局,提供最佳浏览体验。
(1)视口设置(Viewport)
html
<!-- 必须设置:移动端适配基础 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
viewport 参数说明:
| 参数 | 说明 | 示例值 |
|---|---|---|
width |
视口宽度 | device-width |
initial-scale |
初始缩放比例 | 1.0 |
minimum-scale |
最小缩放比例 | 0.5 |
maximum-scale |
最大缩放比例 | 5.0 |
user-scalable |
是否允许缩放 | yes/no |
常见错误:
html
<!-- 错误:未设置 viewport,导致移动端缩放异常 -->
<html>
<head>
<title>移动端页面</title>
<!-- 缺少 viewport -->
</head>
</html>
(2)响应式图片
html
<!-- 方案1:srcset 根据屏幕密度 -->
<img
src="small.jpg"
srcset="small.jpg 480w, medium.jpg 800w, large.jpg 1200w"
sizes="(max-width: 480px) 100vw, (max-width: 800px) 50vw, 33vw"
alt="响应式图片"
>
<!-- 方案2:picture 元素根据条件加载 -->
<picture>
<source media="(max-width: 480px)" srcset="mobile.jpg">
<source media="(max-width: 768px)" srcset="tablet.jpg">
<img src="desktop.jpg" alt="响应式图片">
</picture>
(3)媒体查询(CSS 配合)
html
<!-- HTML 中通过 media 属性控制样式表 -->
<link rel="stylesheet" href="mobile.css" media="screen and (max-width: 480px)">
<link rel="stylesheet" href="desktop.css" media="screen and (min-width: 769px)">
(4)相对单位使用
html
<!-- 使用相对单位而非固定像素 -->
<div style="width: 50%; max-width: 600px;">
<p style="font-size: 1.2rem;">相对单位文本</p>
</div>
19. 移动端适配的常用方法有哪些?
适配方法对比:
| 方法 | 原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| Viewport适配 | 设置 viewport meta | 简单直接 | 仅控制缩放 | 所有移动端页面 |
| rem适配 | 根据根字号缩放 | 统一比例 | 需计算 | 复杂移动页面 |
| vw/vh适配 | 视口单位 | 天然响应 | 兼容性 | 现代项目 |
| 媒体查询 | 断点适配 | 灵活控制 | 断点维护 | 响应式网站 |
| 弹性布局 | Flexbox/Grid | 自动分配 | 学习成本 | 各类布局 |
rem 适配方案:
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
// 动态设置根字号
const fontSize = window.innerWidth / 10;
document.documentElement.style.fontSize = fontSize + 'px';
</script>
</head>
<body>
<div style="font-size: 0.16rem;">内容</div>
</body>
</html>
vw/vh 适配方案:
html
<style>
/* 基于设计稿 375px 宽度 */
.box {
width: 50vw; /* 占视口宽度50% */
height: 26.67vh; /* 占视口高度26.67% */
font-size: 4.27vw; /* 16px / 375px * 100vw */
}
</style>
十二、渐进增强与优雅降级
20. 渐进增强 vs 优雅降级的区别是什么?
定义:
| 概念 | 定义 | 设计方向 |
|---|---|---|
| 渐进增强(Progressive Enhancement) | 先保证基础功能在所有浏览器可用,再为高级浏览器增强体验 | 自下而上 |
| 优雅降级(Graceful Degradation) | 先为高级浏览器构建完整功能,再确保旧浏览器基本可用 | 自上而下 |
对比表格:
| 维度 | 渐进增强 | 优雅降级 |
|---|---|---|
| 起点 | 基础功能 | 完整功能 |
| 目标 | 提升高级浏览器体验 | 保证旧浏览器可用 |
| 开发顺序 | 核心功能 → 增强功能 | 完整功能 → 降级方案 |
| 兼容性 | 更好 | 一般 |
| 维护成本 | 较低 | 较高 |
| 推荐度 | 推荐 | 传统做法 |
渐进增强示例:
html
<!-- 第一层:基础 HTML(所有设备) -->
<a href="/submit-form">提交表单</a>
<!-- 第二层:CSS 增强(支持 CSS 的设备) -->
<style>
a {
display: inline-block;
padding: 10px 20px;
background: #007bff;
color: white;
border-radius: 4px;
text-decoration: none;
}
</style>
<!-- 第三层:JavaScript 增强(支持 JS 的设备) -->
<script>
// 使用 Ajax 提交,提供更好的体验
document.querySelector('a').addEventListener('click', (e) => {
e.preventDefault();
fetch('/api/submit', { method: 'POST' })
.then(res => res.json())
.then(data => showSuccess());
});
</script>
优雅降级示例:
html
<!-- 第一层:完整功能(现代浏览器) -->
<form id="contactForm">
<input type="email" required pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$">
<button type="submit">提交</button>
</form>
<script>
// 现代浏览器使用 HTML5 验证 + Ajax
const form = document.getElementById('contactForm');
form.addEventListener('submit', (e) => {
e.preventDefault();
// 提交逻辑
});
</script>
<!-- 第二层:降级方案(旧浏览器) -->
<!--[if lt IE 10]>
<noscript>
<p>您的浏览器不支持 JavaScript,请升级或使用表单直接提交。</p>
<form action="/submit" method="POST">
<input type="text" name="email">
<button type="submit">提交</button>
</form>
</noscript>
<![endif]-->
选择策略:
- 新项目推荐使用渐进增强:确保核心内容可访问
- 遗留项目可能需要优雅降级:在完整功能基础上做兼容
- 实际开发中两者常结合使用
十三、无障碍访问(A11Y)
21. 无障碍化实现方法
定义: 无障碍访问(Accessibility,简称 A11Y)是指让残障用户也能正常使用网页的设计原则。
核心实现方法:
(1)语义化标签
html
<!-- 正确:使用语义化标签 -->
<button>点击我</button>
<a href="/">链接</a>
<!-- 错误:使用 div 模拟 -->
<div onclick="submit()">点击我</div> <!-- 无法键盘导航 -->
(2)ARIA 属性
html
<!-- ARIA 角色 -->
<div role="navigation">
<ul>
<li><a href="/">首页</a></li>
</ul>
</div>
<!-- ARIA 状态 -->
<button aria-expanded="false" aria-controls="menu">
菜单
</button>
<ul id="menu" role="menu" aria-hidden="true">
<li role="menuitem">选项1</li>
</ul>
<!-- ARIA 标签 -->
<input type="text" aria-label="搜索产品">
<!-- ARIA 描述 -->
<input type="password" aria-describedby="pwd-hint">
<span id="pwd-hint">密码至少8个字符</span>
<!-- ARIA 实时区域 -->
<div aria-live="polite" role="status">
表单提交成功!
</div>
(3)键盘导航
html
<!-- tabindex 控制焦点顺序 -->
<button tabindex="1">第一步</button>
<button tabindex="2">第二步</button>
<!-- 确保所有交互元素可聚焦 -->
<a href="/">链接</a>
<button>按钮</button>
<input type="text">
<select>
<option>选项</option>
</select>
<!-- 非交互元素添加键盘支持 -->
<div
role="button"
tabindex="0"
onclick="handleClick()"
onkeydown="if(event.key==='Enter')handleClick()"
>
可键盘操作的元素
</div>
(4)焦点管理
html
<style>
/* 自定义焦点样式 */
:focus {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
/* 移除鼠标点击时的焦点样式,保留键盘焦点 */
:focus:not(:focus-visible) {
outline: none;
}
</style>
(5)颜色对比度
html
<!-- 确保文本和背景对比度至少 4.5:1 -->
<style>
.accessible-text {
color: #333333; /* 深色文本 */
background: #ffffff; /* 白色背景 */
/* 对比度约 12.6:1,符合 WCAG AA */
}
</style>
常见无障碍问题及解决:
| 问题 | 影响 | 解决方案 |
|---|---|---|
| 缺少 alt 属性 | 屏幕阅读器无法描述图片 | 添加有意义的 alt 文本 |
| 缺少表单 label | 用户不知道输入什么 | 使用 <label> 关联 |
| 纯颜色传递信息 | 色盲用户无法理解 | 添加图标或文字说明 |
| 无键盘导航 | 无法使用鼠标者 | 确保所有功能可键盘操作 |
| 自动播放媒体 | 干扰辅助技术 | 提供暂停/停止控制 |
十四、HTML 空元素
22. HTML 空元素有哪些?
定义: 空元素(Void Elements),也称自闭合元素,是指没有内容、不需要结束标签的 HTML 元素。
完整列表:
html
<br> <!-- 换行 -->
<hr> <!-- 水平线 -->
<img> <!-- 图片 -->
<input> <!-- 输入控件 -->
<link> <!-- 外部资源链接 -->
<meta> <!-- 元数据 -->
<area> <!-- 图像映射区域 -->
<base> <!-- 基准URL -->
<col> <!-- 表格列 -->
<embed> <!-- 嵌入内容 -->
<param> <!-- 对象参数 -->
<source> <!-- 媒体资源 -->
<track> <!-- 字幕轨道 -->
<wbr> <!-- 换行机会 -->
使用示例:
html
<!-- 正确写法(HTML5) -->
<br>
<img src="photo.jpg" alt="照片">
<hr>
<input type="text">
<!-- XHTML 写法(自闭合) -->
<br />
<img src="photo.jpg" alt="照片" />
<!-- 错误写法(空元素不应有结束标签) -->
<br></br> <!-- 错误 -->
<img src="photo.jpg"></img> <!-- 错误 -->
十五、性能优化
23. 前端性能优化的常用方法有哪些(从 HTML、CSS、JavaScript 等多方面考虑)?
多维度优化策略:
HTML 层面
html
<!-- 1. 资源预加载 -->
<link rel="preload" href="font.woff2" as="font" crossorigin>
<link rel="prefetch" href="next-page.html">
<link rel="preconnect" href="https://fonts.googleapis.com">
<!-- 2. 图片优化 -->
<img src="small.jpg" loading="lazy" alt="图片"> <!-- 懒加载 -->
<!-- 3. 脚本加载优化 -->
<script src="app.js" defer></script> <!-- DOM 解析完成后执行 -->
<script src="analytics.js" async></script> <!-- 下载完立即执行 -->
<!-- 4. 减少 DOM 复杂度 -->
<!-- 避免过深的嵌套,减少节点数量 -->
<!-- 5. 使用 CDN -->
<script src="https://cdn.example.com/jquery.min.js"></script>
<!-- 6. 多域名存储资源 -->
<!-- 利用浏览器并发限制,不同域名资源可并行下载 -->
<img src="https://cdn1.example.com/img1.jpg">
<img src="https://cdn2.example.com/img2.jpg">
<img src="https://cdn3.example.com/img3.jpg">
多域名存储资源的优化原理:
- 浏览器对同一域名有并发请求限制(通常 6-8 个)
- 使用多个域名可绕过限制,实现并行下载
- 注意:域名解析有开销,一般 2-4 个域名为宜
CSS 层面
html
<!-- 1. 关键 CSS 内联 -->
<style>
/* 首屏关键样式直接内联 */
.header { background: #fff; }
</style>
<!-- 2. 非关键 CSS 异步加载 -->
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
<!-- 3. 避免 @import -->
<!-- @import 会串行加载,应使用多个 link 标签 -->
JavaScript 层面
html
<!-- 1. 脚本置底或 defer/async -->
<script src="app.js" defer></script>
<!-- 2. 按需加载 -->
<script>
// 动态导入
import('./module.js').then(module => {
module.init();
});
</script>
<!-- 3. 防抖与节流 -->
<script>
// 防抖:事件触发后延迟执行
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// 节流:固定时间间隔内只执行一次
function throttle(fn, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
</script>
24. 多域名存储资源的优化原理
原理说明:
- 浏览器对同一域名(协议 + 域名 + 端口)的并发连接数有限制
- HTTP/1.1 标准建议最多 6 个并发连接
- 通过将静态资源分散到多个子域名,可以突破限制
示例:
html
<!-- 单域名:受并发限制 -->
<img src="https://static.example.com/img1.jpg">
<img src="https://static.example.com/img2.jpg">
<!-- 最多同时加载6个,其余排队 -->
<!-- 多域名:突破限制 -->
<img src="https://static1.example.com/img1.jpg">
<img src="https://static2.example.com/img2.jpg">
<img src="https://static3.example.com/img3.jpg">
<img src="https://static4.example.com/img4.jpg">
<!-- 最多可同时加载约24个资源 -->
注意事项:
- HTTP/2 已支持多路复用,单域名也可并行下载
- 多域名会增加 DNS 解析开销
- 现代项目建议优先考虑 HTTP/2,而非多域名分片
十六、图片格式选择
25. 图片格式选择(PNG/JPG/GIF 适用场景)
格式对比:
| 格式 | 特点 | 压缩类型 | 透明度 | 动画 | 适用场景 |
|---|---|---|---|---|---|
| JPG/JPEG | 色彩丰富,体积小 | 有损压缩 | 不支持 | 不支持 | 照片、复杂图像 |
| PNG | 无损,支持透明 | 无损压缩 | 支持 | 不支持 | Logo、图标、截图 |
| GIF | 支持简单动画 | 无损压缩(256色) | 支持 | 支持 | 简单动画、表情包 |
| WebP | 现代格式,体积小 | 有损/无损 | 支持 | 支持 | 通用替代 |
| SVG | 矢量,无限缩放 | - | 支持 | 支持 | 图标、Logo、图表 |
| AVIF | 最新格式,压缩率极高 | 有损/无损 | 支持 | 支持 | 未来通用格式 |
选择策略:
html
<!-- 照片类:JPG 或 WebP -->
<img src="photo.jpg" alt="风景照片">
<!-- Logo/图标:SVG 或 PNG -->
<img src="logo.svg" alt="公司Logo">
<!-- 复杂截图:PNG -->
<img src="screenshot.png" alt="软件界面截图">
<!-- 简单动画:GIF 或 WebP -->
<img src="animation.gif" alt="操作演示动画">
<!-- 响应式图片:使用 picture 元素 -->
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="图片">
</picture>
十七、微格式
26. 什么是微格式(Microformats)?
定义: 微格式(Microformats)是一种简单的数据标记方法,通过在 HTML 中添加特定的 class 名称,使机器能理解页面内容的语义。
原理:
- 使用预定义的 class 名称标注内容
- 基于已有的 HTML 元素,不引入新标签
- 搜索引擎和工具可以提取结构化数据
常见微格式示例:
html
<!-- hCard:联系信息 -->
<div class="vcard">
<span class="fn">张三</span>
<span class="org">公司名称</span>
<a class="email" href="mailto:zhangsan@example.com">zhangsan@example.com</a>
<span class="tel">+86-138-0000-0000</span>
<span class="adr">
<span class="street-address">某街道123号</span>
<span class="locality">北京市</span>
</span>
</div>
<!-- hEntry:博客文章 -->
<div class="hentry">
<h2 class="entry-title">文章标题</h2>
<span class="published">2024-03-15</span>
<span class="author">
<span class="fn">作者名</span>
</span>
<div class="entry-content">
<p>文章内容...</p>
</div>
</div>
<!-- hReview:评价 -->
<div class="hreview">
<span class="item">
<span class="fn">产品名称</span>
</span>
<span class="rating">4.5</span>
<span class="summary">很好用</span>
<p class="description">产品使用体验...</p>
</div>
微格式与 Schema.org 对比:
| 特性 | 微格式(Microformats) | Schema.org |
|---|---|---|
| 语法 | HTML class 属性 | HTML 属性或 JSON-LD |
| 复杂度 | 简单 | 更丰富 |
| 支持度 | 逐渐减少 | 主流搜索引擎支持 |
| 推荐度 | 传统方案 | 推荐使用 |
现代替代方案(JSON-LD):
html
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Person",
"name": "张三",
"email": "zhangsan@example.com",
"telephone": "+86-138-0000-0000",
"address": {
"@type": "PostalAddress",
"streetAddress": "某街道123号",
"addressLocality": "北京市"
}
}
</script>
十八、实战问题排查
27. 移动端视口:未设置 <meta name="viewport"> 导致缩放异常
问题描述: 在移动端浏览器中,如果没有设置 viewport meta 标签,页面会按桌面宽度渲染,导致内容缩放异常。
原因分析:
- 移动浏览器默认使用约 980px 的视口宽度
- 页面内容会被缩小以适应屏幕
- 文字过小,需要手动放大查看
解决方案:
html
<!-- 必须添加到 <head> 中 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
参数解释:
width=device-width:视口宽度等于设备宽度initial-scale=1.0:初始缩放比例为 1:1maximum-scale=5.0:最大允许放大 5 倍user-scalable=yes:允许用户缩放(提升可访问性)
28. 表单验证:防抖处理或错误提示样式缺失
问题描述:
- 表单输入验证时,每次输入都触发验证,性能差且体验不佳
- 验证失败时缺少清晰的错误提示
解决方案:
html
<!-- 防抖验证 -->
<form id="myForm">
<div class="form-group">
<label for="email">邮箱</label>
<input
type="email"
id="email"
name="email"
required
pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"
>
<span class="error-message" role="alert"></span>
</div>
<button type="submit">提交</button>
</form>
<style>
.form-group { margin-bottom: 16px; }
input:invalid:not(:placeholder-shown) {
border-color: #dc3545;
}
input:valid:not(:placeholder-shown) {
border-color: #28a745;
}
.error-message {
color: #dc3545;
font-size: 12px;
display: none;
}
.error-message.visible {
display: block;
}
</style>
<script>
// 防抖验证
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
const emailInput = document.getElementById('email');
const errorMsg = emailInput.nextElementSibling;
const validateEmail = debounce((value) => {
const regex = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$/i;
if (value && !regex.test(value)) {
errorMsg.textContent = '请输入有效的邮箱地址';
errorMsg.classList.add('visible');
emailInput.setAttribute('aria-invalid', 'true');
emailInput.setAttribute('aria-describedby', 'email-error');
} else {
errorMsg.textContent = '';
errorMsg.classList.remove('visible');
emailInput.setAttribute('aria-invalid', 'false');
}
}, 300);
emailInput.addEventListener('input', (e) => validateEmail(e.target.value));
</script>
29. 无障碍(A11Y):缺少 ARIA 标签或键盘导航
问题描述:
- 自定义组件缺少 ARIA 属性,屏幕阅读器无法正确解读
- 无法通过键盘操作自定义交互元素
解决方案:
html
<!-- 自定义下拉菜单的无障碍实现 -->
<div class="custom-dropdown">
<button
type="button"
aria-haspopup="listbox"
aria-expanded="false"
aria-controls="dropdown-list"
id="dropdown-trigger"
>
选择选项
</button>
<ul
id="dropdown-list"
role="listbox"
aria-labelledby="dropdown-trigger"
hidden
>
<li role="option" aria-selected="false" tabindex="-1">选项1</li>
<li role="option" aria-selected="false" tabindex="-1">选项2</li>
<li role="option" aria-selected="false" tabindex="-1">选项3</li>
</ul>
</div>
<script>
const trigger = document.getElementById('dropdown-trigger');
const list = document.getElementById('dropdown-list');
trigger.addEventListener('click', () => {
const isExpanded = trigger.getAttribute('aria-expanded') === 'true';
trigger.setAttribute('aria-expanded', !isExpanded);
list.hidden = isExpanded;
});
// 键盘导航
trigger.addEventListener('keydown', (e) => {
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault();
trigger.click();
}
});
</script>
30. SEO 不友好:SPA 未使用 SSR(如 Next.js)
问题描述: 单页应用(SPA)初始加载时只有空的 HTML 结构,内容通过 JavaScript 动态渲染,搜索引擎爬虫可能无法正确索引内容。
解决方案:
html
<!-- 方案1:服务端渲染(SSR) -->
<!-- 使用 Next.js、Nuxt.js 等框架 -->
<!-- 服务器直接返回完整 HTML -->
<!-- 方案2:预渲染(Pre-rendering) -->
<!-- 构建时生成静态 HTML -->
<!-- 方案3:动态渲染 -->
<!-- 对爬虫返回服务端渲染内容,对用户返回 SPA -->
<!-- 方案4:使用 History API 而非 Hash 路由 -->
<!-- 坏:#/about -->
<!-- 好:/about -->
Next.js SSR 示例:
jsx
// pages/index.js (Next.js)
export async function getServerSideProps() {
const data = await fetch('https://api.example.com/data');
return { props: { data } };
}
export default function Home({ data }) {
return (
<div>
<h1>{data.title}</h1>
<p>{data.content}</p>
</div>
);
}