HTML5 的新特性有哪些?
簡約版本:
“HTML5 新特性主要體現在六個方面:
第一,語義化標簽,比如 header、footer、nav 等,讓頁面結構更清晰;
第二,表單增強,新增了 date、email 等類型和 placeholder、required 等屬性;
第三,多媒體支持,提供了 audio 和 video 標簽,不再依賴 Flash;
第四,圖形繪制,有 canvas 和 svg;
第五,本地存儲,提供了 localStorage 和 sessionStorage;
第六,一些新的 API,比如 WebSocket 實時通信、Web Worker 多線程、地理定位、拖拽 API 和 History API 等。
總體來說,HTML5 更加語義化、增強了交互體驗,也提高了性能和可用性。”
詳細版本:
主要分為 語義化標簽、表單增強、多媒體支持、圖形繪制、本地存儲、API 六大類:
語義化標簽
新增結構標簽:
header
、footer
、nav
、section
、article
、aside
、main
作用:提升頁面語義,利于 SEO 和可訪問性
表單增強
新的表單控件:
date
、email
、url
、number
、range
、color
、search
新的屬性:
required
、placeholder
、pattern
、autofocus
多媒體支持
原生音視頻標簽:
<audio>
、<video>
支持多種格式,不依賴 Flash
圖形繪制
canvas
:支持 2D 圖形繪制svg
:矢量圖形支持
本地存儲
localStorage
:長期存儲,容量比 cookie 大sessionStorage
:會話級存儲
新的 API
地理定位:
navigator.geolocation
拖放 API:
drag & drop
Web Worker:多線程處理
WebSocket:雙向實時通信
History API:控制瀏覽器歷史記錄
ARIA / 無障礙開發面試題 & 答案
Q1. 什么是 ARIA?
ARIA(Accessible Rich Internet Applications)是一組 HTML 屬性,主要以 aria-
開頭。它的作用是幫助輔助技術(比如屏幕閱讀器)理解頁面結構和交互狀態。
在現代前端中,我們經常用自定義組件(比如用 div
模擬按鈕),這些元素本身沒有語義,屏幕閱讀器讀不懂。ARIA 就是用來補充語義信息,讓頁面對殘障用戶更加友好。
👉 可以補充一句:ARIA 不會改變視覺效果,只影響輔助技術的理解。
Q2. 常見的 ARIA 屬性有哪些?舉例
1.角色(role):定義元素的語義角色,幫助輔助技術識別它是什么。
banner
(頁面頭部)navigation
(導航區域)main
(主要內容)complementary
(補充內容)contentinfo
(頁腳信息)search
(搜索區域)button
(按鈕)checkbox
(復選框)radio
(單選按鈕)tab
(選項卡)tabpanel
(選項卡面板)tooltip
(提示信息)dialog
(對話框)article
(文章)heading
(標題)list
(列表)listitem
(列表項)table
(表格)等等
2. 狀態/屬性(aria-*):描述元素當前狀態,比如展開/選中/禁用等。
aria-label
:給元素添加描述信息。aria-hidden
:讓讀屏器忽略某個元素。aria-expanded
:表示菜單是否展開。aria-checked
:復選框是否選中。aria-live
:提示動態區域,讀屏器會自動播報內容更新。
<div role="button" aria-pressed="false" tabindex="0">點我
</div>
//role="button" → 讓它被識別為按鈕
//tabindex="0" → 允許鍵盤 Tab 聚焦
//aria-pressed="false" → 狀態(未按下)
Q3. 開發無障礙應用時,ARIA 和語義化 HTML 有什么關系?
最佳實踐是 優先使用語義化 HTML 標簽(比如 <button>
、<nav>
、<header>
),因為瀏覽器和讀屏器天然支持。
ARIA 是 補充手段,當我們用自定義組件(比如 div
寫的按鈕)時,再用 role
和 aria-*
屬性來增強可訪問性。
一句話總結:能用原生標簽就用原生,實在不行才用 ARIA。
Q4. 如何讓自定義組件可訪問?
- 給組件加
role
(補充語義)。 - 用
aria-*
屬性描述狀態(比如展開、禁用、選中)。 - 確保 鍵盤可操作,加
tabindex="0"
并監聽 Enter/Space 鍵事件。 - 動態內容要用
aria-live
或role="alert"
提示用戶。
👉 這樣屏幕閱讀器和鍵盤用戶都能正常使用。
Q5. 在實際工作中,你做過哪些可訪問性優化?
參考回答:(隨便挑 2–3 點說)
用語義化標簽代替純
div
/span
,比如<button>
。給圖片加
alt
,給圖標加aria-hidden="true"
。自定義組件時,補充
role
和aria-*
屬性。處理鍵盤可訪問性(Tab 聚焦、Enter/Space 觸發)。
動態提示(比如表單報錯)用
aria-live
讓讀屏器播報。
Q6. ARIA 有什么使用原則?
參考回答:
能用 HTML 原生語義就用原生,不要過度依賴 ARIA。
只在必要時添加,避免屬性過多導致讀屏器混亂。
測試可訪問性:實際用屏幕閱讀器(NVDA、VoiceOver)和鍵盤來測試。
CSS 相關問題
1. CSS 選擇器的優先級是怎么計算的?
👉 內聯樣式 > ID 選擇器 > 類 / 屬性 / 偽類選擇器 > 標簽選擇器 > 通配符 > 繼承 > 瀏覽器默認樣式。
數值記憶法:行內(1000) > ID(100) > 類/偽類(10) > 標簽/偽元素(1)。
2. 標準盒模型和 IE 盒模型有什么區別?
👉 標準盒模型:width
只包含 content,不含 padding 和 border。
👉 IE 盒模型:width
包含 content + padding + border。
元素總寬度 = content + padding + border + margin
元素總高度 = content + padding + border + margin
box-sizing: content-box; /* 標準盒模型(默認) */
box-sizing: border-box; /* 怪異盒模型 */
3.如何創建響應式布局?
👉 媒體查詢(Media Queries):根據不同屏幕寬度設置不同的樣式。
/* 默認樣式:移動端優先 */
.container { font-size: 14px; }/* 平板端 */
@media (min-width: 768px) {.container { font-size: 16px; }
}/* PC 端 */
@media (min-width: 1200px) {.container { font-size: 18px; }
}
👉 流式布局(Fluid Layout):使用百分比 %
、視口單位 vw/vh
、彈性單位 em/rem
等,而不是固定 px
。
👉?彈性盒子(Flexbox):用 flex
讓子元素在父容器中自動適應。
👉網格布局(CSS Grid):Grid 天生適合響應式布局。?自動根據屏幕寬度決定列數。
.grid {display: grid;grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));gap: 20px;
}
👉響應式圖片 / 媒體:使用 max-width: 100%
讓圖片不超出容器。
👉移動端適配(viewport 設置):確保在不同設備上縮放正常。
<meta name="viewport" content="width=device-width, initial-scale=1.0">
移動端優先 是主流做法:先寫小屏,再通過媒體查詢適配大屏。
4. position 的值有哪幾種?區別是什么?
static:默認定位,不受 top/left 影響。
relative:相對自身定位,占據原位置。
absolute:相對最近的非 static 祖先定位。
fixed:相對瀏覽器窗口定位,不隨滾動條移動。
sticky:結合 relative 和 fixed,根據滾動位置切換。
5. z-index 為什么有時不起作用?
沒有定位屬性
z-index
只在元素設置了定位(position: relative | absolute | fixed | sticky
)時才生效。如果是
position: static
(默認),z-index
不會起作用。
層疊上下文(Stacking Context)影響
元素所在的層疊上下文會限制它的
z-index
效果。每個層疊上下文內部的元素
z-index
只在自己“上下文”里比較,無法跨層疊上下文提升。觸發層疊上下文的情況(常見):
設置了
position
且z-index
值不是auto
;設置了
opacity < 1
;設置了
transform
、filter
、perspective
、clip-path
等屬性;設置了
isolation: isolate
。
父子關系影響
子元素的
z-index
受限于父元素所在的層疊上下文,即使子元素z-index
再大,也不會覆蓋在父元素所在層疊上下文之外的兄弟元素之上。
瀏覽器默認層疊順序
如果
z-index
相同或沒設置,瀏覽器會按照以下順序疊放:背景和邊框(最底層)
負
z-index
元素塊級元素(按 HTML 順序)
浮動元素
行內元素(按 HTML 順序)
正
z-index
元素(數值越大越靠上)
6.如何實現水平垂直居中?
- 使用 Flex 布局(推薦 ?)
.parent {display: flex;justify-content: center; /* 水平居中 */align-items: center; /* 垂直居中 */
}
.child {width: 100px;height: 100px;
}
- 使用 Grid 布局
.parent {display: grid;place-items: center; /* 水平 + 垂直居中 */
}
- 絕對定位 + transform
.parent {position: relative;
}
.child {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);
}
- 絕對定位 + margin auto
.parent {position: relative;
}
.child {position: absolute;top: 0; bottom: 0;left: 0; right: 0;margin: auto;width: 100px;height: 100px;
}
- 傳統方法:表格布局 / line-height
//第一。表格法(適合文字/小組件):.parent {display: table-cell;text-align: center; /* 水平 */vertical-align: middle; /* 垂直 */
}// 第二。line-height 法(適合單行文本):.parent {height: 100px;line-height: 100px; /* 設置等于高度 */text-align: center;
}
7. 什么是 BFC?有什么作用?
👉定義
BFC 全稱 Block Formatting Context(塊級格式化上下文)。
它是頁面中的一個獨立渲染區域,內部元素的布局不會影響到區域外部。
👉如何觸發 BFC(常見幾種方式)
設置
float
值(left
/right
,但不是none
)。設置
position
為absolute
/fixed
。設置
display
為inline-block
、table-cell
、flex
、grid
等。設置
overflow
為hidden
、auto
、scroll
。
👉 BFC 的特性 / 作用
清除浮動:父元素觸發 BFC 后,可以包含子元素的浮動,不會出現高度塌陷。
避免外邊距重疊(margin collapse):同一個 BFC 內的塊級元素上下
margin
會重疊,不同 BFC 之間則不會。隔離作用:BFC 區域和外部獨立,內部元素不會影響外部布局。
自適應兩欄布局:利用 BFC 可以實現一邊浮動一邊自適應。
👉 常見應用場景
? 清除浮動問題
? 阻止
margin
合并? 實現多欄布局(左側固定寬度,右側自適應)
JavaScript 作用域 & 閉包
1. 什么是作用域?有哪些類型?
作用域(Scope)是指程序中變量和函數的可訪問范圍。
JavaScript 的作用域類型主要有:
全局作用域:在代碼最外層聲明的變量和函數,整個程序都可以訪問。
函數作用域:每個函數調用時都會創建自己的作用域,函數內部定義的變量只能在函數內部訪問。
塊級作用域:
let
和const
聲明的變量只在代碼塊{}
內有效,例如 if、for 中。
👉 JavaScript 采用 詞法作用域(在函數定義時就決定了作用域,而不是運行時)。
2. 什么是作用域鏈?
當訪問一個變量時,JavaScript 引擎會:
先在當前作用域查找
如果找不到,就沿著外層作用域逐級向上查找
直到全局作用域,如果還沒找到,就拋出
ReferenceError
這種 逐級查找的鏈條 就叫 作用域鏈。
👉 本質:函數持有外部作用域的引用。
3. 什么是執行上下文(Execution Context)?
執行上下文是 JavaScript 代碼運行時的環境。
每次執行一段代碼時,都會創建一個執行上下文,包括:
變量環境(var 聲明的變量、函數聲明)
詞法環境(let、const 聲明的變量)
this 綁定(當前執行環境的 this 指向)
執行上下文分為三類:
全局上下文(頁面首次運行時創建,只有一個)
函數上下文(每次調用函數時都會創建)
eval 上下文(eval 代碼執行時創建,不推薦使用)
4. 什么是變量提升?
JavaScript 在代碼執行前,會先進行“預編譯”階段:
var
聲明的變量會提升到作用域頂端,默認值是undefined
。函數聲明(function declaration)會整體提升,可以在聲明前調用。
let
和const
也會提升,但存在 暫時性死區(TDZ),在聲明前使用會報錯。
console.log(a); // undefined
var a = 10;console.log(b); // ReferenceError
let b = 20;
5.this 在不同場景下的指向是什么?
普通函數調用 → 在非嚴格模式下指向全局對象(
window
),嚴格模式下是undefined
。對象方法調用 → 指向調用該方法的對象。
構造函數調用(new) → 指向新創建的實例對象。
顯式綁定 → 使用
call
、apply
、bind
可以手動指定 this。箭頭函數 → 沒有自己的 this,繼承外層作用域的 this。
6. 什么是閉包?
閉包是指一個函數與其周圍的詞法環境(變量和狀態)的綁定。通過閉包,函數可以訪問其外部作用域中的變量,即使在外部函數執行結束后,這些變量依然可以被內部函數訪問和使用。
閉包的本質是函數與其定義時的作用域環境的結合。當一個函數返回另一個函數時,返回的內部函數會保留對外部函數作用域的引用,從而形成閉包。
條件(記三個字:函數 + 引用)
必須有 函數嵌套
內部函數 用到了外部變量
外部函數執行完,但變量 仍被引用
作用:
數據持久化:能夠讓某些變量長期保存在內存中,實現狀態的記憶。
封裝與私有化:利用閉包,可以模擬私有變量,避免外部隨意修改。
函數式編程:閉包是實現回調函數、高階函數、函數工廠等的重要基礎。
缺點:
(1)容易在循環中出 bug(var
導致所有閉包共享同一個變量)
(1)循環里的閉包問題
for (var i = 0; i < 3; i++) {setTimeout(() => console.log(i), 1000);
}
// 輸出:3 3 3原因:var i 是同一個函數作用域,閉包引用的是同一個 i解決方法:for (let i = 0; i < 3; i++) {setTimeout(() => console.log(i), 1000);
}
// 輸出:0 1 2或者使用 IIFE(立即執行函數):for (var i = 0; i < 3; i++) {((i) => {setTimeout(() => console.log(i), 1000);})(i);
}
(2)內存泄漏
閉包持有外部函數的變量引用,如果使用不當,可能導致內存不能及時釋放。
7. 為什么閉包會導致內存泄漏?
因為閉包會讓外部函數的變量一直被引用,垃圾回收機制(GC)無法釋放這部分內存。
解決方法:
在不需要閉包時,將其引用置為
null
避免過度使用閉包
8. 閉包的實際應用場景有哪些?
(1)封裝私有變量
function Counter() {let count = 0;return {inc: () => ++count,dec: () => --count};
}
(2)事件處理器(回調函數中訪問外部變量)
(3)函數柯里化(currying)
function add(a) {return function(b) {return a + b;};
}
9. 什么是事件循環(Event Loop)?宏任務和微任務有什么區別?
JavaScript 是單線程的,采用 事件循環機制 來處理異步任務。
執行順序:
先執行 同步代碼(主線程)。
同步執行完后,檢查 微任務隊列(microtask queue),依次執行完。
微任務清空后,再執行一個 宏任務(macrotask)。
重復以上過程,形成循環。
常見宏任務(macrotask): setTimeout
、setInterval
、setImmediate
、I/O、UI 渲染。
常見微任務(microtask): Promise.then/catch/finally
、MutationObserver
、queueMicrotask
、process.nextTick(Node)
。
👉 口訣:先同步 → 再微任務 → 再宏任務。
10. 什么是原型和原型鏈?
原型(prototype):
每個函數都有一個prototype
屬性,用于存放實例共享的方法和屬性。原型鏈(Prototype Chain):
對象在查找屬性時,會先在自己本身查找,如果沒有,就沿著__proto__
向上查找父級原型,直到Object.prototype
,再到null
停止。
function Person() {}
const p = new Person();
console.log(p.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
👉 原型鏈的本質是 對象屬性查找機制。
11. async / await 的底層原理是什么?
async/await
是 ES2017 引入的語法糖,用來寫異步代碼。async
函數默認返回一個Promise
。await
用來等待一個Promise
的結果,函數會“暫停”執行,等結果出來再繼續。👉 作用:讓異步代碼寫起來更像同步代碼,可讀性更好。
底層原理:
async/await
是Promise
的語法糖,本質是基于 Promise + Generator 實現的。await
會暫停函數的執行,把后續代碼放進微任務隊列,等Promise
完成后再繼續執行。
👉 關鍵點:await
會把后續代碼放到 微任務隊列。
12.??Promise 是什么?解決了什么問題?
Promise
是 ES6 引入的一種 異步編程的解決方案,用于表示一個可能在未來某個時間點才會完成的操作結果。本質是一個 狀態機,有三種狀態:
pending
(進行中)、fulfilled
(已成功)、rejected
(已失敗),且狀態 不可逆。Promise
提供了統一的.then/.catch/.finally
接口,使得我們可以通過鏈式調用來組織異步代碼。
解決的問題:
(1)回調地獄(Callback Hell)
傳統異步依賴多層嵌套回調,代碼難以維護;
Promise
通過鏈式調用讓異步邏輯更加扁平化、清晰。
(2)錯誤處理分散
回調模式下錯誤需要逐層處理;
Promise
支持 錯誤冒泡,集中用.catch
捕獲異常。
(3)異步流程控制
Promise.all / race / allSettled / any
提供了強大的并發控制能力,方便管理多個異步任務。