该内容主要整理关于 HTML 的相关面试题,其他内容面试题请移步至 「最新最全的前端面试题集锦」 查看。
HTML模块精选篇
- 1. 如何理解HTML语义化
- 2. H5的新特性有哪些
- 3. 说一下 HTML5 Drag API
- 4. iframe有那些缺点
- 5. 如何实现浏览器内多个标签页之间的通信
- 6. 简述一下src与href的区别
- 7. 网页制作会用到的图片格式有哪些
- 8. script标签中defer和async的区别
- 9. 说一下 web worker
- 10. 用一个div模拟textarea的实现
- 11. 介绍下资源预加载 prefetch/preload
- 12. 介绍下 viewport
- 13. 如何解决a标点击后hover事件失效的问题?
- 14. 点击一个input依次触发的事件
- 15. 有写过原生的自定义事件吗
- 16. addEventListener和attachEvent的区别?
- 17. addEventListener函数的第三个参数
- 18. DOM事件流是什么?
- 19. 冒泡和捕获的具体过程
- 20. 关于一些兼容性
- 21. 如何阻止冒泡和默认事件(兼容写法)
- 22. 所有的事件都有冒泡吗?
- 23. 拖拽有哪些知识点
- 24. offset、scroll、client的区别
- 25. target="_blank"有哪些问题?
- 26. children以及childNodes的区别
- 27. HTMLCollection和NodeList的区别
1. 如何理解HTML语义化
- 用正确的标签做正确的事情。
- HTML语义化就是让页面的内容结构化,便于对浏览器、搜索引擎解析。
- 在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读。
- 搜索引擎的爬虫依赖于标记来确定上下文和各个关键字的权重,利于 SEO。
- 使阅读源代码的人对网站更容易将网站分块,便于阅读维护理解。
2. H5的新特性有哪些
-
拖放(
Drag)API【🔎下面有详细讲解 => 3】 -
画布(
Canvas) AP -
地理(
Geolocation) API -
音频、视频API(
audio,video) -
localStorage和sessionStorage -
WebWorker,WebSocket【🔎下面有详细讲解 => 2】 -
新的一套标签
header,nav,footer,aside,article,section -
web worker是运行在浏览器后台的js程序,他不影响主程序的运行,是另开的一个js线程,可以用这个线程执行复杂的数据操作,然后把操作结果通过postMessage传递给主线程,这样在进行复杂且耗时的操作时就不会阻塞主线程了 -
HTML5 History两个新增的API:
history.pushState和history.replaceState,两个 API 都会操作浏览器的历史记录,而不会引起页面的刷新Hash就是 url 中看到#,我们需要一个根据监听哈希变化触发的事件(hashchange) 事件。我们用window.location处理哈希的改变时不会重新渲染页面,而是当作新页面加到历史记录中,这样我们跳转页面就可以在hashchange事件中注册ajax从而改变页面内容。 可以为hash的改变添加监听事件:window.addEventListener("hashchange", funcRef, false -
WebSocket使用ws或wss协议,WebSocket是一个持久化的协议,相对于HTTP这种非持久的协议来说。WebSocketAPI最伟大之处在于服务器和客户端可以在给定的时间范围内的任意时刻,相互推送信息。WebSocket并不限于以Ajax(或XHR)方式通信,因为Ajax技术需要客户端发起请求,而WebSocket服务器和客户端可以彼此相互推送信息;XHR受到域的限制,而WebSocket允许跨域通信。// 创建一个Socket实例 var socket = new WebSocket('ws://localhost:8080'); // 打开Socket socket.onopen = function(event) { // 发送一个初始化消息 socket.send('I am the client and I\'m listening!'); // 监听消息 socket.onmessage = function(event) { console.log('Client received a message',event); }; // 监听Socket的关闭 socket.onclose = function(event) { console.log('Client notified socket has closed',event); }; } // 关闭Socket.... // socket.close()
3. 说一下 HTML5 Drag API
- 被拖动元素可以触发的事件
dragstart:在开始拖放被拖放元素时触发(拖拽开始)darg:在正在拖放被拖放元素时触发(拖拽事件)dragend:在整个拖放操作结束时触(拖拽结束)
- 拖动到的目标对象可以触发的事件
dragenter:在被拖放元素进入某元素时触发(拖拽进入)dragover:在被拖放在某元素内移动时触发(悬浮事件)dragleave:在被拖放元素移出目标元素时触发(拖拽离开)drop:在目标元素停止拖拽时触发(丢弃事件)【需要在dragover中调用e.preventDefault();才能触发drop】
4. iframe有那些缺点
iframe会阻塞主页面的onLoad事件;- 搜索引擎的检索程序无法解读这种页面,不利于SEO;
iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载;- 使用
iframe之前需要考虑这两个缺点。如果需要使用iframe,最好是通过j,动态给iframe添加src属性。
5. 如何实现浏览器内多个标签页之间的通信
- 使用
WebSocket可以实现多个标签页之间的通信 - 调用
localStorage- 在一个标签页里面使用
localStorage.setItem(key,value)添加(修改、删除)内容 - 在另一个标签页里面监听
storage事件 - 即可得到
localstorge存储的值,实现不同标签页之间的通信
- 在一个标签页里面使用
- 调用
cookie+setInterval()将要传递的信息存储在
cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息。
具体demo见【】
6. 简述一下src与href的区别
-
src用于替换当前元素,href用于在当前文档和引用资源之间确立联系。 -
src是source的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;在请求src资源时会将其指向的资源下载并应用到文档内,例如js脚本,img图片和frame等元素<script src =”index.js”></script当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,img 图片和frame等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将js脚本放在底部而不是头部
-
href是Hypertext Reference的缩写,指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,如果我们在文档中添加<link href=”common.css” rel=”stylesheet”/>那么浏览器会识别该文档为css文件,就会并行下载资源并且不会停止对当前文档的处理。这也是为什么建议使用
link方式来加载css,而不是使用@import方式。
7. 网页制作会用到的图片格式有哪些
png-8,png-24,jpeg,gif,svg,WebP(🌟)
Webp:WebP格式,谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG的2/3,并能节省大量的服务器带宽资源和数据空间。Facebook Ebay等知名网站已经开始测试并使用WebP格式。
在质量相同的情况下,WebP格式图像的体积要比JPEG格式图像小40%
8. script标签中defer和async的区别
script:会阻碍HTML解析,只有下载好并执行完脚本才会继续解析HTML。defer:浏览器指示脚本在文档被解析后执行,script被异步加载后并不会立刻执行,而是等待文档被解析完毕后执行。async:同样是异步加载脚本,区别是脚本加载完毕后立即执行,这导致async属性下的脚本是乱序的,对于script有先后依赖关系的情况,并不适用

蓝色线代表网络读取,红色线代表执行时间,这俩都是针对脚本的;绿色线代表 HTML 解析
9. 说一下 web worker
在
HTML页面中,如果在执行脚本时,页面的状态是不可响应式的,直到脚本执行完成后, 页面才变成可响应。web worker是运行在后台的 js,独立于其他脚本,不会影响页面你的性能。并且通过postMessage将结果回传到主线程。这样在进行复杂操作的时候,就不会阻塞主线程了
如何创建 web worker
10. 用一个div模拟textarea的实现
给 div 添加 contenteditable=true 即可
11. 介绍下资源预加载 prefetch/preload
都是告知浏览器提前加载文件(图片、视频、js、css等),但执行上是有区别的。
-
prefetch:利用浏览器空闲时间来下载或预取用户在不久的将来可能访问的文档。<link href="/js/xx.js" rel="prefetch"> -
preload:可以指明哪些资源是在页面加载完成后即刻需要的,浏览器在主渲染机制介入前就进行预加载,这一机制使得资源可以更早的得到加载并可用,且更不易阻塞页面的初步渲染,进而提升性能。<link href="/js/xxx.js" rel="preload" as="script">需要
as指定资源类型目前可用的属性类型:audio:音频video: 视频文件。document:一个将要被嵌入到<frame>或<iframe>内部的HTML文档。embed: 一个将要被嵌入到<embed>元素内部的资源。fetch: 那些将要通过fetch和XHR请求来获取的资源,比如一个ArrayBuffer或JSON文件。font: 字体文件。image: 图片文件。object: 一个将会被嵌入到<embed>元素内的文件。script: JavaScript文件。style: 样式表。track: WebVTT文件worker: 一个JavaScript的web worker或shared worker
12. 介绍下 viewport
<meta name="viewport" content="width=500, initial-scale=1">
width:页面宽度,可以取值具体的数字,也可以是device-width,表示跟设备宽度相等。height:页面高度,可以取值具体的数字,也可以是device-height,表示跟设备高度相等。initial-scale:初始缩放比例。minimum-scale:最小缩放比例。maximum-scale:最大缩放比例。user-scalable:是否允许用户缩放。
13. 如何解决a标点击后hover事件失效的问题?
改变 a 标签 css 属性的排列顺序
只需要记住LoVe HAte原则就可以了(爱恨原则)
link → visited → hover → activ
// 注意各个阶段的含义
- a:link:未访问时的样式,一般省略成a
- a:visited:已经访问后的样式
- a:hover:鼠标移上去时的样式
- a:active:鼠标按下时的样式
14. 点击一个input依次触发的事件
mouseenter -> mousedown -> focus -> click
const text = document.getElementById('text');
text.onclick = function (e) {
console.log('onclick')
}
text.onfocus = function (e) {
console.log('onfocus')
}
text.onmousedown = function (e) {
console.log('onmousedown')
}
text.onmouseenter = function (e) {
console.log('onmouseenter')
}
答案:
'onmouseenter'
'onmousedown'
'onfocus'
'onclick'
15. 有写过原生的自定义事件吗
创建自定义事件
原生自定义事件有三种写法:
-
使用
Eventconst myEvent = new Event('event_name') -
使用
customEvent(可以传参数)const myEvent = new CustomEvent('event_name', { detail: { // 将需要传递的参数放到这里 // 可以在监听的回调函数中获取到:event.detail } }) -
使用
document.createEvent('CustomEvent')和initCustomEvent()// createEvent:创建一个事件 const myEvent = document.createEvent('CustomEvent'); // 注意这里是为'CustomEvent // initEvent:初始化一个事件 myEvent.initEvent( // initEvent可以指定3个参数: // 1. event_name: 事件名称 // 2. canBubble: 是否冒泡 // 3. cancelable: 是否可以取消默认行为 )
事件的监听
自定义事件的监听其实和普通事件的一样,使用 addEventListener 来监听:
button.addEventListener('event_name', function (e) {}
事件的触发
触发自定义事件使用 dispatchEvent(myEvent)
注意⚠️ 这里的参数是要自定义事件的对象(也就是myCustomEvent),而不是自定义事件的名称('myEvent')
👇 看案例
const myCustomEvent = document.createEvent('CustomEvent');
myCustomEvent.initEvent('myEvent', true, true)
const btn = document.getElementsByTagName('button')[0]
btn.addEventListener('myEvent', function (e) {
console.log(e)
console.log(e.detail)
})
setTimeout(() => {
btn.dispatchEvent(myCustomEvent)
}, 2000)
16. addEventListener和attachEvent的区别?
详细可见文章:一文彻底搞懂JS的事件流以及事件模型
addEventListener是标准浏览器中的用法,attachEvent是IE8以下addEventListener可有冒泡,可有捕获;attachEvent只有冒泡,没有捕获。addEventListener事件名不带on,attachEvent带onaddEventListener回调函数中的this指向当前元素,attachEvent指向window
17. addEventListener函数的第三个参数
详细可见文章:一文彻底搞懂JS的事件流以及事件模型
第三个参数涉及到冒泡和捕获,是 true 时为捕获,是 false 则为冒泡。
也可以是一个对象
{passive: true},针对的是Safari浏览器,禁止/开启使用滚动的时候要用到。
18. DOM事件流是什么?
详细可见文章:一文彻底搞懂JS的事件流以及事件模型
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程就叫做DOM事件流。
DOM事件流分为三个阶段:
-
捕获阶段:事件从window发出,自上而下向目标节点传播的阶段
-
目标阶段:真正的目标阶段正在处理事件的阶段
-
冒泡阶段:事件从目标节点自下而上向window传播的阶段
(注意⚠️:JS代码只能执行捕获或者冒泡其中一个阶段,要么是捕获要么是冒泡)
19. 冒泡和捕获的具体过程
详细可见文章:一文彻底搞懂JS的事件流以及事件模型
冒泡指的是:当给某个目标元素绑定了事件之后,这个事件会依次在它的父级元素中被触发(当然前提是这个父级元素也有这个同名称的事件,比如子元素和父元素都绑定了click事件就触发父元素的click)。
捕获则是从上层向下层传递,与冒泡相反。
【非常好记,你就想想水底有一个泡泡从下面往上传的,所以是冒泡】
👇 看案例
<!-- 会依次执行 button li ul -->
<ul onclick="alert('ul')">
<li onclick="alert('li')">
<button onclick="alert('button')">点击</button>
</li>
</ul>
<script>
window.addEventListener('click', function (e) {
alert('window')
},false)
document.addEventListener('click', function (e) {
alert('document')
},true)
</script>
结果:
冒泡结果:button > li > ul > document > window
捕获结果:window > document > ul > li > button
20. 关于一些兼容性
-
event的兼容性- 其它浏览器
window.event - 火狐下没有
window.event,所以用传入的参数ev代替 - 兼容写法:
const oEvent = ev || window.event
- 其它浏览器
-
事件源的兼容性
- 其它浏览器
event.target - IE下为
event.srcElement - 兼容写法:
const target = event.target || event.srcElement
- 其它浏览器
-
阻止事件冒泡
- 其它浏览器
event.stopPropagation() - IE下为
window.event.cancelBubble = true
- 其它浏览器
-
阻止默认事件
- 其它浏览器
e.preventDefault() - IE下为
window.event.returnValue = false
- 其它浏览器
21. 如何阻止冒泡和默认事件(兼容写法)
阻止冒泡:
// 阻止冒泡
function stopBubble (e) {
if (e && e.stopPropagation) {
e.stopPropagation();
} else {
// 兼容 IE
window.event.cancelBubble = true;
}
}
// 阻止默认事件
function stopDefault (e) {
if (e && e.preventDefault) {
e.preventDefault();
} else {
// 兼容 IE
window.event.returnValue = false;
return false;
}
}
22. 所有的事件都有冒泡吗?
并不是所有的事件都有冒泡的。
以下事件就没有:
onbluronfocusonmouseenteronmouseleave
23. 拖拽有哪些知识点
- 可以通过给标签设置
draggable属性来实现元素的拖拽,img和a标签默认是可以拖拽的 - 拖拽者身上的三个事件:
ondragstart、ondrag、ondragend - 拖拽要放到的元素上的四个事件:
ondragenter、ondragover、ondragleave、ondrap
24. offset、scroll、client的区别
offset
offsetWidth是指div的宽度(包括div的边框)offsetHeight是指div的高度(包括div的边框)offsetLeft是指div到整个页面左边框的距离(不包括div的边框)offsetTop是指div到整个页面上边框的距离(不包括div的边框)
scroll
scrollTop是指可视区顶部边框与整个页面上部边框的看不到的区域。scrollLeft是指可视区左边边框与整个页面左边边框的看不到的区域。scrollWidth是指左边看不到的区域加可视区加右边看不到的区域即整个页面的宽度(包括边框)scrollHeight是指上边看不到的区域加可视区加右边看不到的区域即整个页面的高度(包括边框)
client
oEvent.clientX是指鼠标到可视区左边框的距离。oEvent.clientY是指鼠标到可视区上边框的距离。clientWidth是指可视区的宽度。clientHeight是指可视区的高度。clientLeft获取左边框的宽度。clientTop获取上边框的宽度。
25. target="_blank"有哪些问题?
存在问题:
- 安全隐患:新打开的窗口可以通过
window.opener获取到来源页面的window对象即使跨域也可以。某些属性的访问被拦截,是因为跨域安全策略的限制。 但是,比如修改window.opener.location的值,指向另外一个地址,这样新窗口有可能会把原来的网页地址改了并进行页面伪装来欺骗用户。 - 新打开的窗口与原页面窗口共用一个进程,若是新页面有性能不好的代码也会影响原页面。
解决方案:
- 尽量不用
target="_blank" - 如果一定要用,需要加上
rel="noopener"或者rel="noreferrer"。这样新窗口的window.openner就是null了,而且会让新窗口运行在独立的进程里,不会拖累原来页面的进程。(不过,有些浏览器对性能做了优化,即使不加这个属性,新窗口也会在独立进程打开。)
26. children以及childNodes的区别
children只获取该节点下的所有element节点childNodes不仅仅获取element节点还会获取元素标签中的空白节点firstElementChild只获取该节点下的第一个element节点firstChild会获取空白节点
27. HTMLCollection和NodeList的区别
Node 和 Element
DOM是一棵树,所有节点都是NodeNode是Element的基类Element是其他HTML元素的基类,如HTMLDivElement、HTMLImageElement等
👇 结构图

HTMLCollection是Element的集合NodeList是Node的集合,包含Text和Comment节点ele.children返回HTMLCollection集合ele.childNodes返回NodeList集合HTMLCollection和NodeList是类数组- 使用
Array.from(list)转化数组 - 使用
Array.prototype.slice.call(list)转化数组 - 使用
[...list]转化数组
- 使用
<p id="p1"><b>node</b> vs <em>element</em><!--注释--></p>
<script>
const p1 = document.getElementById('p1')
// console.log(p1.children) // HTMLCollection
console.log(p1.childNodes) // NodeList
// p1.tagName // Element类型一定有tagName
// p1.nodeType/nodeName // node节点
class Node {}
// document
class Document extends Node {}
class DocumentFragment extends Node {}
// 文本和注释
class CharacterData extends Node {}
class Comment extends CharacterData {}
class Text extends CharacterData {}
// elem
class Element extends Node {}
class HTMLElement extends Element {}
class HTMLDivElement extends HTMLElement {}
class HTMLInputElement extends HTMLElement {}
// ...
</script>



















