HTML 面试题
前端面试题 - HTML篇
本文档系统整理了前端面试中HTML相关的核心知识点,涵盖HTML5新特性、DOM操作、表单验证、可访问性、SEO、性能优化等多个维度。
📋 文档说明
面试中HTML的重要性
HTML作为前端开发的三大基石之一,在面试中占据重要地位:
- 基础能力考察:体现候选人对Web标准的理解程度
- 工程化思维:通过语义化、可访问性等考察代码质量意识
- 性能优化视角:DOM操作、资源加载优化是高级面试必考点
- 综合素养评估:SEO、兼容性处理体现项目经验
题目统计
| 统计项 | 数量 |
|---|---|
| 总题数 | 50道 |
| 基础题 | 15道 (30%) |
| 中级题 | 25道 (50%) |
| 高级题 | 10道 (20%) |
难度标识说明
- ⭐ 基础:HTML基础概念,适合初级面试
- ⭐⭐ 中级:需要理解原理,适合1-3年经验
- ⭐⭐⭐ 高级:综合应用和优化,适合3年以上经验
目录
- 一、HTML5新特性
- 二、DOM操作和事件机制
- 三、表单和验证
- 四、可访问性(Accessibility/A11y)
- 五、SEO优化
- 六、性能优化
- 七、常见兼容性问题
- 八、综合题目
- 复习建议与学习资源
一、HTML5新特性
1.1 语义化标签
1. 什么是HTML语义化?为什么要使用语义化标签?
难度:⭐(基础)
标签:#语义化 #HTML5 #最佳实践
问题描述:
请解释HTML语义化的概念,并说明在实际开发中使用语义化标签的好处。
参考答案要点:
- 语义化是指使用恰当的HTML标签来展示内容结构,让标签具有明确的含义
- 主要好处:
- 可读性:提高代码可读性和可维护性,便于团队协作
- SEO优化:搜索引擎更容易理解页面结构和内容重要性
- 可访问性:屏幕阅读器能正确解析页面,帮助视障用户
- 开发效率:结构清晰,便于后期维护和迭代
2. HTML5新增了哪些语义化标签?请举例说明
难度:⭐(基础)
标签:#HTML5 #语义化标签
问题描述:
列举HTML5新增的语义化标签,并说明每个标签的适用场景。
参考答案要点:
<header>:定义页面或区块的头部,通常包含logo、导航等<nav>:定义导航链接区域<article>:定义独立的文章内容,可独立分发<section>:定义文档中的节或区块,有主题的内容分组<aside>:定义侧边栏内容,与主内容相关的辅助信息<footer>:定义页面或区块的底部<main>:定义文档的主要内容(每个页面只有一个)<figure>/<figcaption>:定义图文组合及标题<time>:定义日期/时间<mark>:定义高亮文本
代码示例:
<body>
<header>
<h1>网站标题</h1>
<nav>
<a href="/">首页</a>
<a href="/about">关于</a>
</nav>
</header>
<main>
<article>
<header>
<h2>文章标题</h2>
<time datetime="2024-01-01">2024年1月1日</time>
</header>
<section>
<p>文章内容...</p>
</section>
</article>
<aside>
<h3>相关推荐</h3>
<ul>
...
</ul>
</aside>
</main>
<footer>
<p>© 2024 版权所有</p>
</footer>
</body>3. HTML5与HTML4的主要区别是什么?
难度:⭐⭐(中级)
标签:#HTML5 #HTML4 #对比
问题描述:
对比HTML5和HTML4,说明HTML5带来的主要改进和新增特性。
参考答案要点:
| 特性 | HTML4 | HTML5 |
|---|---|---|
| DOCTYPE | 复杂冗长 | <!DOCTYPE html> |
| 语义化 | 主要用div | 新增header、nav、article等 |
| 多媒体 | 依赖Flash | 原生audio、video标签 |
| 表单 | 类型有限 | email、date、number等 |
| 存储 | Cookie | localStorage、sessionStorage |
| 绘图 | 不支持 | Canvas、SVG |
| API | 有限 | Geolocation、Web Workers等 |
4. 如何处理HTML5新标签的浏览器兼容问题(IE8及以下)?
难度:⭐⭐(中级)
标签:#兼容性 #HTML5 #IE
问题描述:
IE8及以下浏览器不支持HTML5新标签,如何解决这个问题?
参考答案要点:
- 使用html5shiv库:最流行的解决方案
- 手动创建元素:
document.createElement('header') - 添加默认样式:新标签需要设置为块级元素
代码示例:
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<![endif]-->
<style>
/* 确保新标签在旧IE中显示为块级元素 */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
</style>1.2 Canvas与SVG
5. Canvas和SVG有什么区别?
难度:⭐⭐(中级)
标签:#Canvas #SVG #图形
问题描述:
对比Canvas和SVG两种图形技术,说明它们的区别和适用场景。
参考答案要点:
| 特性 | Canvas | SVG |
|---|---|---|
| 绘制方式 | 基于像素的位图 | 基于矢量的XML |
| 缩放 | 放大会失真 | 缩放不失真 |
| 事件处理 | 需要手动计算坐标 | 每个元素可独立绑定事件 |
| 适用场景 | 游戏、图像处理、像素操作 | 图标、图表、Logo |
| 性能 | 适合大量图形渲染 | 适合少量复杂图形 |
| SEO | 不可搜索 | 文本可搜索 |
6. Canvas的基本使用方法是什么?
难度:⭐⭐(中级)
标签:#Canvas #绘图
问题描述:
请演示Canvas的基本使用流程,包括获取上下文和绘制简单图形。
参考答案要点:
- 通过
getContext('2d')获取2D渲染上下文 - 支持绘制矩形、路径、文本、图像等
- 支持变换、渐变、阴影等效果
代码示例:
<canvas id="myCanvas" width="500" height="300"></canvas>
<script>
var canvas = document.getElementById("myCanvas")
var ctx = canvas.getContext("2d")
// 绘制矩形
ctx.fillStyle = "green"
ctx.fillRect(10, 10, 150, 50)
// 绘制圆形
ctx.beginPath()
ctx.arc(250, 150, 50, 0, 2 * Math.PI)
ctx.fillStyle = "blue"
ctx.fill()
// 绘制文本
ctx.font = "20px Arial"
ctx.fillStyle = "black"
ctx.fillText("Hello Canvas", 10, 100)
</script>1.3 本地存储
7. localStorage、sessionStorage和Cookie的区别?
难度:⭐(基础)
标签:#存储 #localStorage #Cookie
问题描述:
对比三种客户端存储方式的特点和适用场景。
参考答案要点:
| 特性 | localStorage | sessionStorage | Cookie |
|---|---|---|---|
| 生命周期 | 永久(手动清除) | 页面关闭清除 | 可设置过期时间 |
| 存储大小 | ~5-10MB | ~5-10MB | ~4KB |
| 与服务端通信 | 不自动发送 | 不自动发送 | 每次请求自动携带 |
| 作用域 | 同源 | 同源+同标签页 | 可设置domain/path |
| 适用场景 | 用户偏好设置、主题 | 临时表单数据 | 登录状态Token |
代码示例:
// localStorage
localStorage.setItem("username", "张三")
localStorage.getItem("username")
localStorage.removeItem("username")
localStorage.clear()
// sessionStorage
sessionStorage.setItem("tempData", "临时数据")
// Cookie
document.cookie = "name=value; expires=Thu, 18 Dec 2024 12:00:00 UTC; path=/"8. 为什么sessionStorage在不同Tab页之间不共享?
难度:⭐⭐(中级)
标签:#sessionStorage #浏览器原理
问题描述:
解释sessionStorage的隔离机制,以及为什么设计成这样。
参考答案要点:
- 这是W3C标准的刻意设计,核心原则是隔离而非共享
- 每个Tab/Window有独立的顶级浏览上下文
- sessionStorage的设计初衷是存储会话级别的临时数据
- 特殊情况:通过
window.open或链接打开新页面时,新页面会复制原页面的sessionStorage
9. localStorage的storage事件是什么?如何使用?
难度:⭐⭐(中级)
标签:#localStorage #事件 #跨标签页通信
问题描述:
解释storage事件的作用和使用场景,并给出代码示例。
参考答案要点:
- 当其他标签页修改localStorage时触发
- 可用于跨标签页通信
- 重要特性:当前页面修改不会触发,只有其他页面修改才会触发
代码示例:
// 监听storage事件
window.addEventListener("storage", (e) => {
console.log("变化的key:", e.key)
console.log("旧值:", e.oldValue)
console.log("新值:", e.newValue)
console.log("发生变化的页面URL:", e.url)
console.log("存储区域:", e.storageArea)
})
// 应用场景:一个标签页登录,其他标签页同步登录状态1.4 Web Workers与Service Workers
10. Web Worker的作用是什么?如何使用?
难度:⭐⭐⭐(高级)
标签:#WebWorker #多线程 #性能
问题描述:
解释Web Worker的作用,并说明使用方法和限制。
参考答案要点:
- 作用:在后台线程中运行JavaScript,不阻塞主线程
- 适用场景:复杂计算、大数据处理、图像处理等耗时操作
- 重要限制:无法访问DOM,不能操作页面元素
代码示例:
// main.js - 主线程
// 创建Worker
var worker = new Worker("worker.js")
// 发送数据到Worker
worker.postMessage({ numbers: [1, 2, 3, 4, 5] })
// 接收Worker返回的数据
worker.onmessage = function (e) {
console.log("计算结果:", e.data)
}
// 处理错误
worker.onerror = function (error) {
console.error("Worker错误:", error)
}
// 终止Worker
worker.terminate()// worker.js - Worker线程
self.onmessage = function (e) {
var numbers = e.data.numbers
var result = numbers.reduce((a, b) => a + b, 0)
// 将结果发送回主线程
self.postMessage(result)
}11. Service Worker是什么?有什么应用场景?
难度:⭐⭐⭐(高级)
标签:#ServiceWorker #PWA #离线缓存
问题描述:
解释Service Worker的概念、特点,并列举典型应用场景。
参考答案要点:
- 定义:一种特殊的Web Worker,充当Web应用与浏览器之间的代理服务器
- 核心特点:
- 独立于主线程运行
- 可拦截网络请求
- 支持离线缓存
- 支持推送通知
- 应用场景:
- PWA(渐进式Web应用)
- 离线访问
- 后台同步
- 推送通知
12. HTML5离线存储(Application Cache)如何使用?
难度:⭐⭐(中级)
标签:#离线存储 #AppCache
问题描述:
说明Application Cache的使用方法和manifest文件结构。
参考答案要点:
- 在html标签添加
manifest属性 - manifest文件包含CACHE、NETWORK、FALLBACK三个部分
- 注意:AppCache已被废弃,推荐使用Service Workers
代码示例:
<html manifest="demo.appcache"></html>CACHE MANIFEST
# 版本号:v1.0
CACHE:
js/app.js
css/style.css
images/logo.png
NETWORK:
*
api/
FALLBACK:
/ /offline.html1.5 多媒体与API
13. HTML5的video和audio标签有哪些常用属性?
难度:⭐(基础)
标签:#多媒体 #video #audio
问题描述:
列举video和audio标签的常用属性及其作用。
参考答案要点:
| 属性 | 作用 |
|---|---|
controls | 显示播放控件(播放、暂停、音量等) |
autoplay | 自动播放 |
loop | 循环播放 |
muted | 静音 |
preload | 预加载策略(auto/metadata/none) |
poster | 视频封面图(video专用) |
width/height | 设置播放器尺寸 |
代码示例:
<!-- 视频 -->
<video controls width="640" height="360" poster="cover.jpg">
<source src="video.mp4" type="video/mp4" />
<source src="video.webm" type="video/webm" />
您的浏览器不支持视频播放。
</video>
<!-- 音频 -->
<audio controls preload="metadata">
<source src="audio.mp3" type="audio/mpeg" />
<source src="audio.ogg" type="audio/ogg" />
您的浏览器不支持音频播放。
</audio>14. Web Components包含哪些核心技术?
难度:⭐⭐⭐(高级)
标签:#WebComponents #组件化 #自定义元素
问题描述:
介绍Web Components的四大核心技术,并给出简单示例。
参考答案要点:
- Custom Elements:定义自定义HTML元素
- Shadow DOM:封装组件内部结构和样式,实现隔离
- HTML Templates:定义可复用的HTML模板
- Slots:创建可插入内容的占位符
代码示例:
// 定义自定义元素
class MyComponent extends HTMLElement {
constructor() {
super()
// 创建Shadow DOM
this.attachShadow({ mode: "open" })
// 定义模板
this.shadowRoot.innerHTML = `
<style>
div { color: blue; padding: 10px; }
</style>
<div>自定义组件内容</div>
<slot></slot>
`
}
connectedCallback() {
console.log("组件被添加到DOM")
}
}
// 注册自定义元素
customElements.define("my-component", MyComponent)<!-- 使用自定义元素 -->
<my-component>
<p>这是slot插入的内容</p>
</my-component>二、DOM操作和事件机制
2.1 事件基础
15. 什么是事件冒泡和事件捕获?
难度:⭐(基础)
标签:#事件 #冒泡 #捕获
问题描述:
解释事件冒泡和事件捕获的概念,以及DOM标准事件流的执行顺序。
参考答案要点:
- 事件捕获(Capture Phase):从document → parent → child(从外到内)
- 事件冒泡(Bubble Phase):从child → parent → document(从内到外)
- DOM标准事件流:先捕获再冒泡
- addEventListener第三个参数:
false(默认):事件冒泡阶段触发true:事件捕获阶段触发
代码示例:
// 事件捕获
parent.addEventListener(
"click",
function () {
console.log("parent - 捕获")
},
true
)
// 事件冒泡(默认)
child.addEventListener(
"click",
function () {
console.log("child - 冒泡")
},
false
)
// 点击child时输出顺序:
// 1. parent - 捕获
// 2. child - 冒泡16. 如何阻止事件冒泡和默认事件?
难度:⭐(基础)
标签:#事件 #兼容性
问题描述:
编写兼容各浏览器的代码,实现阻止事件冒泡和阻止默认事件。
参考答案要点:
stopPropagation():阻止事件冒泡preventDefault():阻止默认事件- 需要考虑IE兼容性
代码示例:
// 阻止事件冒泡
function stopBubble(e) {
if (e && e.stopPropagation) {
e.stopPropagation() // 标准浏览器
} else {
window.event.cancelBubble = true // IE兼容
}
}
// 阻止默认事件
function stopDefault(e) {
if (e && e.preventDefault) {
e.preventDefault() // 标准浏览器
} else {
window.event.returnValue = false // IE兼容
}
}
// 使用示例
element.addEventListener("click", function (e) {
stopBubble(e)
stopDefault(e)
})17. 所有事件都有冒泡吗?哪些事件不冒泡?
难度:⭐⭐(中级)
标签:#事件 #冒泡
问题描述:
列举不冒泡的事件类型,并解释原因。
参考答案要点: 不是所有事件都有冒泡,以下事件不冒泡:
blur:元素失去焦点focus:元素获得焦点mouseenter:鼠标进入元素mouseleave:鼠标离开元素load:资源加载完成unload:页面卸载resize:窗口大小改变scroll:滚动
原因:这些事件的设计初衷是关注元素自身的状态变化,不涉及父子元素间的交互传播。
2.2 事件委托
18. 什么是事件委托?有什么优缺点?
难度:⭐⭐(中级)
标签:#事件委托 #性能优化
问题描述:
解释事件委托的原理,分析其优缺点。
参考答案要点:
- 原理:利用事件冒泡,将事件处理程序绑定到父元素而非每个子元素
- 优点:
- 减少内存消耗,节省事件注册数量
- 动态添加的元素自动拥有事件处理
- 减少DOM操作,提高性能
- 缺点:
- 基于冒泡,不冒泡的事件无法委托
- 层级过多可能影响性能
- 可能出现事件误判(需要判断target)
19. 实现一个事件委托函数
难度:⭐⭐(中级)
标签:#事件委托 #代码实现
问题描述:
编写一个通用的事件委托函数。
参考答案要点:
- 使用事件冒泡机制
- 判断事件源是否匹配目标元素类型
- 使用call绑定this指向
代码示例:
/**
* 事件委托函数
* @param {Element} parent - 父元素
* @param {string} childSelector - 子元素选择器
* @param {string} eventType - 事件类型
* @param {Function} callback - 回调函数
*/
function delegate(parent, childSelector, eventType, callback) {
parent.addEventListener(eventType, function (e) {
var target = e.target
// 向上查找匹配的元素
while (target !== parent) {
if (target.matches(childSelector)) {
callback.call(target, e)
return
}
target = target.parentNode
}
})
}
// 使用示例
delegate(document.getElementById("list"), "li", "click", function (e) {
console.log("点击了:", this.innerHTML)
})20. e.target和e.currentTarget的区别?
难度:⭐⭐(中级)
标签:#事件 #DOM
问题描述:
解释事件对象中target和currentTarget的区别。
参考答案要点:
| 属性 | 含义 |
|---|---|
e.target | 触发事件的实际元素(事件源) |
e.currentTarget | 绑定事件处理程序的元素 |
- 在事件委托中:
target是被点击的具体子元素currentTarget是绑定了事件的父元素
代码示例:
document.getElementById("list").addEventListener("click", function (e) {
console.log("target:", e.target) // 被点击的li
console.log("currentTarget:", e.currentTarget) // 绑定了事件的ul#list
})2.3 DOM操作
21. DocumentFragment是什么?与直接操作DOM的区别?
难度:⭐⭐(中级)
标签:#DOM #性能优化 #DocumentFragment
问题描述:
解释DocumentFragment的作用和优势。
参考答案要点:
- DocumentFragment是轻量级的虚拟DOM容器
- 特点:
- 没有父节点,不会被渲染到页面上
- 不会影响页面的回流和重绘
- 优势:批量DOM操作时,先在内存中操作,最后一次性添加到DOM树,只触发一次渲染
代码示例:
// 低效方式 - 每次appendChild都触发回流
for (var i = 0; i < 1000; i++) {
var li = document.createElement("li")
document.getElementById("list").appendChild(li) // 1000次回流!
}
// 高效方式 - 使用DocumentFragment
var fragment = document.createDocumentFragment()
for (var i = 0; i < 1000; i++) {
var li = document.createElement("li")
fragment.appendChild(li) // 内存操作,不触发回流
}
document.getElementById("list").appendChild(fragment) // 只触发1次回流22. 如何高效地操作大量DOM元素?
难度:⭐⭐⭐(高级)
标签:#DOM #性能优化 #大数据
问题描述:
列举优化大量DOM元素操作的方法。
参考答案要点:
- 使用DocumentFragment批量操作
- 使用requestAnimationFrame分批渲染,避免阻塞
- 使用虚拟DOM(React/Vue等框架)
- 使用innerHTML代替多次appendChild
- 先隐藏元素再操作,操作完成后再显示
- 缓存DOM查询结果,避免重复查询
- 使用虚拟列表(只渲染可视区域)
- 防抖/节流控制操作频率
三、表单和验证
3.1 HTML5表单增强
23. HTML5新增了哪些表单输入类型?
难度:⭐(基础)
标签:#表单 #HTML5 #输入类型
问题描述:
列举HTML5新增的表单输入类型。
参考答案要点:
| 类型 | 说明 |
|---|---|
email | 邮箱地址,自动验证格式 |
tel | 电话号码 |
url | URL地址 |
number | 数字,可设置min/max/step |
range | 滑块范围选择器 |
date | 日期选择器 |
time | 时间选择器 |
datetime-local | 本地日期时间 |
color | 颜色选择器 |
search | 搜索框 |
month/week | 月份/周选择器 |
代码示例:
<input type="email" placeholder="请输入邮箱" />
<input type="number" min="0" max="100" step="5" />
<input type="date" min="2024-01-01" max="2024-12-31" />
<input type="color" value="#ff0000" />
<input type="range" min="0" max="100" value="50" />24. HTML5表单有哪些新的属性?
难度:⭐(基础)
标签:#表单 #HTML5
问题描述:
列举HTML5表单的新增属性。
参考答案要点:
| 属性 | 作用 |
|---|---|
placeholder | 输入提示文本 |
required | 必填验证 |
pattern | 正则表达式验证 |
min/max | 数值范围限制 |
step | 数值间隔 |
autofocus | 自动聚焦 |
autocomplete | 自动完成(on/off) |
multiple | 允许多选(file/email) |
novalidate | 关闭表单验证 |
form | 关联外部表单 |
3.2 表单验证
25. HTML5表单验证的API有哪些?
难度:⭐⭐(中级)
标签:#表单验证 #API
问题描述:
介绍HTML5表单验证的相关API。
参考答案要点: 属性:
validationMessage:验证失败时的提示信息validity:验证状态对象willValidate:是否会被验证
validity对象属性:
valid:验证是否通过valueMissing:required验证失败typeMismatch:类型不匹配patternMismatch:pattern验证失败tooLong/tooShort:长度验证失败rangeOverflow/rangeUnderflow:范围验证失败
方法:
checkValidity():执行验证并返回结果setCustomValidity(message):设置自定义错误信息
26. 如何实现自定义表单验证?
难度:⭐⭐(中级)
标签:#表单验证 #自定义验证
问题描述:
编写代码实现自定义表单验证。
参考答案要点:
- 使用
setCustomValidity()设置自定义错误信息 - 使用
checkValidity()检查验证状态 - 结合input事件实时验证
代码示例:
// 自定义验证 - 用户名长度
var input = document.getElementById("username")
input.addEventListener("input", function () {
if (this.value.length < 3) {
this.setCustomValidity("用户名至少3个字符")
} else if (this.value.length > 20) {
this.setCustomValidity("用户名最多20个字符")
} else {
this.setCustomValidity("") // 清空错误信息
}
})
// 表单提交时验证
form.addEventListener("submit", function (e) {
if (!this.checkValidity()) {
e.preventDefault()
// 处理验证失败
console.log("表单验证失败")
}
})27. 表单验证的伪类有哪些?
难度:⭐⭐(中级)
标签:#CSS #表单验证 #伪类
问题描述:
列举与表单验证相关的CSS伪类。
参考答案要点:
| 伪类 | 说明 |
|---|---|
:valid | 验证通过 |
:invalid | 验证失败 |
:required | 必填字段 |
:optional | 可选字段 |
:in-range | 在范围内 |
:out-of-range | 超出范围 |
:read-only | 只读 |
:read-write | 可读写 |
:checked | 已选中(radio/checkbox) |
代码示例:
/* 验证通过的样式 */
input:valid {
border-color: green;
}
/* 验证失败的样式 */
input:invalid {
border-color: red;
}
/* 必填字段 */
input:required {
background-color: #fffacd;
}四、可访问性(Accessibility/A11y)
4.1 基础概念
28. 什么是Web可访问性(A11y)?
难度:⭐(基础)
标签:#可访问性 #A11y #无障碍
问题描述:
解释Web可访问性的概念和重要性。
参考答案要点:
- 可访问性(Accessibility,缩写a11y)是指确保网页内容能够被所有人平等获取和使用
- 目标用户:
- 视障人士(使用屏幕阅读器)
- 听障人士
- 运动障碍人士
- 认知障碍人士
- 好处:
- 提升用户体验
- 符合法律要求(如WCAG标准)
- 扩大用户群体
- 有利于SEO
29. alt属性和title属性的区别?
难度:⭐(基础)
标签:#可访问性 #SEO #图片
问题描述:
对比img标签的alt和title属性的区别。
参考答案要点:
| 属性 | alt | title |
|---|---|---|
| 作用 | 图片无法显示时的替代文本 | 鼠标悬停时的提示信息 |
| SEO | 重要,搜索引擎可识别 | 影响较小 |
| 可访问性 | 屏幕阅读器读取 | 部分屏幕阅读器支持 |
| 使用场景 | 所有图片都应有 | 可选,提供额外说明 |
代码示例:
<img src="photo.jpg" alt="一只橘色的猫在阳光下睡觉" title="点击放大查看" />4.2 ARIA
30. 什么是ARIA?常见的ARIA属性有哪些?
难度:⭐⭐(中级)
标签:#ARIA #可访问性 #无障碍
问题描述:
介绍ARIA的概念和常用属性。
参考答案要点:
- ARIA(Accessible Rich Internet Applications)是一组属性,用于增强Web内容和应用的可访问性
- 当HTML语义化不足时,ARIA可以补充说明元素的角色、状态和属性
常见属性:
| 属性 | 作用 |
|---|---|
role | 定义元素角色(navigation、main、button等) |
aria-label | 为元素提供标签 |
aria-labelledby | 引用其他元素作为标签 |
aria-describedby | 提供额外描述 |
aria-hidden | 隐藏元素不被屏幕阅读器读取 |
aria-expanded | 展开/折叠状态 |
aria-checked | 选中状态 |
aria-disabled | 禁用状态 |
代码示例:
<!-- 自定义按钮 -->
<div role="button" tabindex="0" aria-label="关闭对话框" aria-pressed="false">
X
</div>
<!-- 导航 -->
<nav role="navigation" aria-label="主导航">
<ul>
...
</ul>
</nav>31. 如何隐藏内容但对屏幕阅读器可见?
难度:⭐⭐(中级)
标签:#可访问性 #CSS #屏幕阅读器
问题描述:
实现一种CSS方案,让内容视觉上隐藏但对屏幕阅读器可见。
参考答案要点:
- 与
display: none或visibility: hidden不同 - 该方法隐藏视觉但保留在可访问树中
- 常用于为图标按钮添加文字说明
代码示例:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}<button>
<span class="visually-hidden">搜索</span>
<i class="icon-search"></i>
</button>4.3 键盘导航
32. 如何确保网站支持键盘导航?
难度:⭐⭐(中级)
标签:#可访问性 #键盘导航 #无障碍
问题描述:
列举确保网站支持键盘导航的要点。
参考答案要点:
- 确保所有交互元素可通过Tab键访问
- 合理的Tab顺序(使用
tabindex,推荐值为0或-1) - 提供可见的焦点指示器(focus样式)
- 支持Enter/Space激活按钮和链接
- 支持Esc关闭弹窗和菜单
- 避免键盘陷阱(用户无法通过Tab离开某个区域)
- 提供跳过链接(Skip Link)快速到达主内容
代码示例:
/* 可见的焦点样式 */
:focus {
outline: 2px solid #007bff;
outline-offset: 2px;
}
/* 不要完全移除outline */
:focus:not(:focus-visible) {
outline: none;
}五、SEO优化
5.1 基础优化
33. 前端如何实现SEO优化?
难度:⭐⭐(中级)
标签:#SEO #优化 #前端
问题描述:
从前端角度说明SEO优化的方法。
参考答案要点: 内部优化:
- TDK优化:Title、Keywords、Description
- 语义化HTML标签
- 合理的heading层级(h1-h6表示标题层级)
- 图片alt属性
- 内部链接优化
- 网站内容更新
- 服务器端渲染(SSR)
外部优化:
- 外部链接建设
- 友情链接交换
- 社交媒体推广
34. meta标签对SEO有什么作用?
难度:⭐(基础)
标签:#SEO #meta #HTML
问题描述:
列举常用的meta标签及其SEO作用。
参考答案要点:
代码示例:
<!-- 字符编码 -->
<meta charset="UTF-8" />
<!-- 视口设置(移动端必备) -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- 页面描述(搜索结果展示) -->
<meta name="description" content="页面描述内容,150字以内" />
<!-- 关键词(现代搜索引擎权重降低) -->
<meta name="keywords" content="关键词1, 关键词2" />
<!-- 作者 -->
<meta name="author" content="作者名" />
<!-- 禁止搜索引擎索引 -->
<meta name="robots" content="noindex, nofollow" />
<!-- Open Graph(社交媒体分享) -->
<meta property="og:title" content="标题" />
<meta property="og:description" content="描述" />
<meta property="og:image" content="分享图片URL" />35. 什么是语义化HTML对SEO的影响?
难度:⭐⭐(中级)
标签:#SEO #语义化
问题描述:
说明语义化HTML对SEO的影响。
参考答案要点:
- 帮助搜索引擎理解页面结构和内容重要性
- 重要的内容使用合适的标签(h1-h6表示标题层级)
- 使用nav、article、section等标签明确内容区域
- 提高页面在搜索结果中的展示效果
- 有助于富媒体摘要(Rich Snippets)的生成
- 提升页面在搜索结果中的排名
5.2 结构化数据
36. 什么是结构化数据?如何实现?
难度:⭐⭐⭐(高级)
标签:#SEO #结构化数据 #Schema
问题描述:
解释结构化数据的概念和实现方式。
参考答案要点:
- 结构化数据是一种标准化格式,用于向搜索引擎提供页面内容的详细信息
- 实现方式:
- JSON-LD(推荐,Google首选)
- Microdata
- RDFa
- 常用Schema类型:
- Article(文章)
- Product(产品)
- Organization(组织)
- Person(人物)
- BreadcrumbList(面包屑)
代码示例:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "文章标题",
"author": {
"@type": "Person",
"name": "作者名"
},
"datePublished": "2024-01-01",
"publisher": {
"@type": "Organization",
"name": "出版社"
}
}
</script>六、性能优化
6.1 资源加载优化
37. preload和prefetch的区别?
难度:⭐⭐(中级)
标签:#性能优化 #资源加载 #preload
问题描述:
对比preload和prefetch的区别和使用场景。
参考答案要点:
| 特性 | preload | prefetch |
|---|---|---|
| 目的 | 立即加载当前页面关键资源 | 提前加载将来可能需要的资源 |
| 优先级 | 高优先级 | 低优先级(空闲时加载) |
| 使用场景 | 首屏CSS/JS/字体 | 下一页资源 |
| 对当前页面 | 直接影响加载速度 | 不直接影响 |
代码示例:
<!-- preload - 预加载关键资源 -->
<link rel="preload" href="/styles/main.css" as="style" />
<link rel="preload" href="/scripts/app.js" as="script" />
<link
rel="preload"
href="/fonts/font.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<!-- prefetch - 预加载下一页资源 -->
<link rel="prefetch" href="/scripts/nextpage.js" />
<link rel="prefetch" href="/styles/nextpage.css" />
<!-- preconnect - 预连接DNS -->
<link rel="preconnect" href="https://cdn.example.com" />38. 什么是懒加载?如何实现图片懒加载?
难度:⭐⭐(中级)
标签:#性能优化 #懒加载 #图片
问题描述:
解释懒加载的概念,并给出图片懒加载的实现方案。
参考答案要点:
- 概念:延迟加载页面资源,只在需要时(如进入视口)加载
- 好处:减少首屏加载时间、节省带宽
代码示例:
// 方式1 - Intersection Observer API(推荐)
const images = document.querySelectorAll("img[data-src]")
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
img.removeAttribute("data-src")
observer.unobserve(img)
}
})
})
images.forEach((img) => observer.observe(img))<!-- 方式2 - 原生懒加载(现代浏览器支持) -->
<img src="placeholder.jpg" data-src="real.jpg" loading="lazy" alt="描述" />39. 懒加载和预加载的区别?
难度:⭐(基础)
标签:#性能优化 #加载策略
问题描述:
对比懒加载和预加载的区别。
参考答案要点:
| 特性 | 懒加载 | 预加载 |
|---|---|---|
| 加载时机 | 按需加载,延迟加载 | 提前加载 |
| 目的 | 减少首屏加载时间 | 提升后续访问速度 |
| 适用场景 | 非关键资源(图片、视频) | 关键资源、下一页资源 |
| 带宽影响 | 节省带宽 | 消耗额外带宽 |
6.2 渲染优化
40. 什么是回流(Reflow)和重绘(Repaint)?
难度:⭐⭐(中级)
标签:#性能优化 #渲染 #回流重绘
问题描述:
解释回流和重绘的概念,以及它们的区别。
参考答案要点:
- 回流(Reflow/重排):
- 重新计算元素的几何属性(位置、大小)
- 触发条件:元素尺寸变化、DOM结构变化、窗口大小变化
- 性能开销大
- 重绘(Repaint):
- 重新绘制元素外观(颜色、背景等)
- 不影响布局
- 性能开销相对较小
- 关系:回流一定会触发重绘,重绘不一定会触发回流
41. 如何避免回流和重绘?
难度:⭐⭐⭐(高级)
标签:#性能优化 #渲染 #最佳实践
问题描述:
列举避免回流和重绘的方法。
参考答案要点:
- 使用CSS Transform和Opacity进行动画(GPU加速)
- 批量修改样式(使用className切换,而非逐个修改style)
- 避免频繁读取布局属性(offsetWidth、clientHeight等)
- 使用DocumentFragment批量操作DOM
- 使用will-change属性创建新渲染层
- 使用requestAnimationFrame优化动画
- 避免使用table布局(table的回流成本高)
- 将元素脱离文档流后再进行复杂操作
42. 如何优化大量数据的渲染性能?
难度:⭐⭐⭐(高级)
标签:#性能优化 #大数据 #渲染
问题描述:
列举优化大量数据渲染性能的方法。
参考答案要点:
- 虚拟列表:只渲染可视区域内的元素(如react-window、vue-virtual-scroller)
- 分页加载:分批次请求和渲染数据
- 时间分片:使用requestAnimationFrame分批渲染
- 骨架屏:提升感知性能
- 防抖节流:控制事件触发频率
- Web Workers:数据处理放到后台线程
- Object.freeze:冻结不需要响应式的数据
七、常见兼容性问题
7.1 浏览器差异
43. DOCTYPE的作用是什么?标准模式和怪异模式的区别?
难度:⭐(基础)
标签:#DOCTYPE #兼容性 #渲染模式
问题描述:
解释DOCTYPE的作用,以及标准模式和怪异模式的区别。
参考答案要点:
- DOCTYPE作用:
- 告诉浏览器文档类型和HTML版本
- 决定浏览器的渲染模式
- 标准模式:
- 严格遵循W3C标准
- 使用W3C标准盒模型(width=content)
- 怪异模式(Quirks Mode):
- 模拟旧浏览器行为(主要是IE5.5)
- 使用IE盒模型(width=content+padding+border)
- HTML5 DOCTYPE:
<!DOCTYPE html>
44. 常见的事件兼容性处理有哪些?
难度:⭐⭐(中级)
标签:#兼容性 #事件 #IE
问题描述:
编写兼容各浏览器的事件处理代码。
参考答案要点:
- 获取事件对象
- 获取事件源
- 阻止冒泡和默认事件
- 添加事件监听
代码示例:
// 获取事件对象
var e = event || window.event
// 获取事件源
var target = e.target || e.srcElement
// 阻止冒泡
if (e.stopPropagation) {
e.stopPropagation()
} else {
e.cancelBubble = true
}
// 阻止默认事件
if (e.preventDefault) {
e.preventDefault()
} else {
e.returnValue = false
}
// 添加事件监听
if (element.addEventListener) {
element.addEventListener("click", fn, false)
} else if (element.attachEvent) {
element.attachEvent("onclick", fn)
} else {
element.onclick = fn
}45. IE浏览器有哪些常见的兼容性问题?
难度:⭐⭐(中级)
标签:#兼容性 #IE
问题描述:
列举IE浏览器的常见兼容性问题。
参考答案要点:
- IE6不支持PNG透明:使用滤镜或PNG8格式
- IE盒模型差异:使用
box-sizing: border-box - 获取兄弟元素:不支持
previousElementSibling等 - 事件对象差异:使用
window.event - CSS选择器支持有限:不支持高级选择器
- 不支持ES6新特性:需要polyfill
- Flex/Grid布局支持问题:IE10+部分支持Flex
7.2 移动端兼容
46. 移动端有哪些常见的HTML兼容性问题?
难度:⭐⭐(中级)
标签:#移动端 #兼容性
问题描述:
列举移动端常见的兼容性问题及解决方案。
参考答案要点:
| 问题 | 解决方案 |
|---|---|
| 点击延迟问题(300ms) | 使用fastclick库或touch事件 |
| 软键盘弹出影响布局 | 使用viewport设置或fixed定位 |
| 1px边框问题 | 使用transform缩放或伪元素 |
| 输入框聚焦问题 | 调整scrollIntoView |
| 日期选择器差异 | 使用第三方组件(如picker) |
| 视频自动播放限制 | 需要用户交互触发 |
| iOS橡皮筋效果 | 使用-webkit-overflow-scrolling |
八、综合题目
47. 从输入URL到页面显示发生了什么?
难度:⭐⭐⭐(高级)
标签:#浏览器原理 #网络 #渲染
问题描述:
详细描述从输入URL到页面完整显示的整个过程。
参考答案要点:
- DNS解析:域名解析为IP地址
- TCP连接:三次握手建立连接
- 发送HTTP请求
- 服务器处理请求并返回响应
- 浏览器解析HTML构建DOM树
- 解析CSS构建CSSOM树
- 合并DOM和CSSOM构建渲染树
- 布局(Layout/Reflow)
- 绘制(Paint)
- 合成(Composite)
48. 如何优化首屏加载时间?
难度:⭐⭐⭐(高级)
标签:#性能优化 #首屏加载 #FCP
问题描述:
列举优化首屏加载时间的方法。
参考答案要点:
- 减少HTTP请求(合并资源、使用雪碧图)
- 启用Gzip压缩
- 使用CDN
- 懒加载非关键资源
- 预加载关键资源(preload)
- 服务端渲染(SSR)
- 代码分割和按需加载
- 优化图片(压缩、WebP格式、响应式图片)
- 使用浏览器缓存
- 减少重定向
- 内联关键CSS
- 延迟加载非关键JavaScript
49. 什么是渐进增强和优雅降级?
难度:⭐⭐(中级)
标签:#兼容性 #设计理念
问题描述:
解释渐进增强和优雅降级的概念及区别。
参考答案要点:
| 特性 | 渐进增强 | 优雅降级 |
|---|---|---|
| 思路 | 从基本功能开始,逐步添加高级特性 | 先构建完整功能,再处理兼容性问题 |
| 优先级 | 优先保证基础功能可用 | 高级浏览器获得完整体验 |
| 适用用户 | 适用于所有用户 | 旧浏览器获得基本体验 |
| 开发方式 | 先写基础HTML,再增强 | 先写完整功能,再写兼容代码 |
50. HTML5的拖拽API有哪些事件?
难度:⭐⭐(中级)
标签:#HTML5 #拖拽 #API
问题描述:
列举HTML5拖拽API的事件。
参考答案要点:
| 事件 | 触发时机 |
|---|---|
dragstart | 开始拖拽 |
drag | 拖拽中(持续触发) |
dragenter | 进入目标元素 |
dragover | 在目标元素上移动(持续触发) |
dragleave | 离开目标元素 |
drop | 在目标元素上释放 |
dragend | 拖拽结束 |
代码示例:
var draggedElement = null
// 拖拽源
document
.querySelector(".draggable")
.addEventListener("dragstart", function (e) {
draggedElement = this
e.dataTransfer.effectAllowed = "move"
})
// 放置目标
document.querySelector(".dropzone").addEventListener("dragover", function (e) {
e.preventDefault() // 必须阻止默认行为才能drop
e.dataTransfer.dropEffect = "move"
})
document.querySelector(".dropzone").addEventListener("drop", function (e) {
e.preventDefault()
this.appendChild(draggedElement)
})复习建议与学习资源
📚 复习建议
-
按难度循序渐进
- 初级开发者:重点掌握基础题(⭐)
- 中级开发者:深入理解中级题(⭐⭐)
- 高级开发者:攻克高级题(⭐⭐⭐)
-
重点题目推荐
优先级 题目 原因 🔥🔥🔥 Q47(URL到页面显示) 必考题,考察浏览器原理 🔥🔥🔥 Q48(首屏优化) 性能优化核心 🔥🔥 Q15/Q16(事件机制) DOM基础 🔥🔥 Q7(存储对比) 高频考点 🔥🔥 Q37(preload/prefetch) 性能优化热点 -
学习方法
- 理解原理 > 死记硬背
- 动手实践 > 只看不做
- 结合实际项目 > 孤立学习
🎯 面试技巧
- 回答要有条理:使用"首先...其次...最后"的结构
- 结合项目经验:理论+实践更有说服力
- 承认不知道:遇到不会的问题,诚实说明并表达学习意愿
- 主动扩展:回答完问题后,可以主动补充相关知识点