在日常前端專案開發中,時常會接到這樣的需求:「設計師給了一張完整的台灣各縣市分佈圖(或是商場樓層平面圖、機械零件拆解圖),希望使用者滑鼠點到不同區塊時,能跳轉到對應的介紹頁面。」對於新手來說,第一直覺往往是把圖片切成十幾張碎圖再用 CSS 拼湊,結果一換螢幕尺寸就全盤崩潰。
其實,瀏覽器原生就內建了專門解決這個問題的強大武器——HTML map 標籤(
<map>,即 Client-Side Image Map 客戶端影像地圖)!只要透過一張
<img>搭配 HTML map 標籤(<map>)與<area>標籤,就能在不裁切圖片的前提下,於單張圖片上精準畫出矩形、圓形甚至任意多邊形的互動熱區(Clickable Hotspots)。更有趣的是,<map>在瀏覽器 DOM 樹狀結構中的運作方式與一般標籤截然不同——它的「視覺呈現(<img>)」與「互動熱區節點(<map> > <area>)」在 DOM 樹中是完全分離的兩個分支!這篇筆記就帶你從零認識 HTML map 標籤,徹底打通影像地圖與 DOM 樹的底層對應關係。
⚡ 快速簡單使用(30 秒複製即用範本)
如果你趕時間、只想立刻在圖片上加上可點擊的連結區域,直接複製下方最小可用範本(只需替換圖片路徑 src、座標 coords 與連結 href 即可運作):
<!-- 步驟 1:放上底圖,並加上 usemap="#自訂名稱"(注意開頭一定要有 # 號) -->
<img src="product-banner.jpg" alt="產品導覽圖" width="600" height="400" usemap="#quick-map">
<!-- 步驟 2:建立對應的 <map name="自訂名稱">(注意這裡不能有 # 號) -->
<map name="quick-map" id="quick-map">
<!-- 矩形點擊區 (rect):coords="左上X,左上Y,右下X,右下Y" -->
<area shape="rect" coords="20,20,280,180" href="/product-a" alt="前往產品 A">
<!-- 圓形點擊區 (circle):coords="圓心X,圓心Y,半徑R" -->
<area shape="circle" coords="450,200,80" href="/product-b" alt="前往產品 B">
<!-- 多邊形點擊區 (poly):coords="X1,Y1,X2,Y2,X3,Y3..."(至少 3 個頂點) -->
<area shape="poly" coords="100,250,250,250,175,380" href="/product-c" alt="前往產品 C">
</map>
💡 3 秒修改重點:
<img usemap="#quick-map">的名字必須跟<map name="quick-map">完全相同(一個有#,一個沒有#)。- 座標原點
(0, 0)在圖片左上角,數值單位為像素(px)。
一、 什麼是 HTML map 標籤?5 秒鐘掌握影像地圖鐵三角速查表
在開始寫程式碼之前,我們先用最白話的方式定義 HTML <map> 標籤:<map> 是 HTML 中用來定義「客戶端影像地圖(Image Map)」的容器元素。它必須與 <img> 圖片標籤以及內部的 <area> 熱區標籤三者協同運作,才能在單一圖片上建立多個獨立的可點擊超連結區域。
我們可以將這組「影像地圖鐵三角(<img> + <map> + <area>)」的職責與 DOM 樹特性整理成以下速查表:
| 標籤名稱 | 在影像地圖中的核心職責 | 必備關鍵屬性 | 在 DOM 樹中的節點特性與內容模型 |
|---|---|---|---|
<img> | 視覺像素宿主(Visual Host):負責在畫面上渲染出底圖,並指定要套用哪一張 <map>。 | src, alt, usemap="#地圖名稱"(注意:最前面必須加 # 號) | 空元素(Void Element):在 DOM 樹中不能有任何子節點(無法把 <area> 寫在 <img> 裡面)。 |
<map> | 熱區定義容器(Map Container):負責收納所有的 <area> 座標節點,供 <img> 跨節點引用。 | name="地圖名稱"(不可含 # 號與空白,建議同步加上同名的 id) | 透明內容模型(Transparent):本身在畫面上不佔據獨立空間(預設 display: none),作為 <area> 的父節點。 |
<area> | 幾何互動熱區(Hotspot Node):定義點擊範圍的形狀、像素座標、跳轉連結與無障礙替代文字。 | shape (rect / circle / poly), coords, href, alt | 空元素(Void Element):無結束標籤;雖在 CSS 設為 display: none,卻能接收滑鼠點擊與鍵盤 Tab 焦點! |
二、 為什麼 map 的 DOM 樹結構這麼特別?解析「視覺」與「DOM 節點」的跨節點映射
很多新手第一次寫 <map> 時都會產生一個強烈的疑問:「為什麼 <area> 熱區明明是畫在 <img> 圖片上面,但在 HTML 裡卻不能寫成 <img><area></img>,而要另外包在一個 <map> 標籤裡?」
1. 歷史與規範原因:img 是沒有結束標籤的 Void Element
根據 HTML 元素內容模型規範,<img> 屬於空元素(Void Element),在 HTML5 解析器(Parser)中遇到 <img> 就會立即閉合,根本不允許擁有任何子節點。
因此,W3C 與 WHATWG 設計了一套在整個 HTML 標準中極為罕見的「跨節點引用映射機制(Hash-Name Reference Mapping)」:
- 你在 DOM 樹的某個位置放一張
<img usemap="#taiwan-map">。 - 在 DOM 樹的另一個位置(通常是
<img>的下一個兄弟節點,甚至放在<footer>也能運作)放一個<map name="taiwan-map">,並在裡面塞入多個<area>子節點。 - 瀏覽器渲染引擎會透過
#taiwan-map這個名稱索引,將<map>內所有<area>的幾何座標,虛擬投射疊加(Overlay) 到<img>的畫面座標系上!
2. 視覺化對照:DOM 樹父子階層 vs. 瀏覽器畫面碰撞偵測層 (Hit-Testing)
讓我們透過下方的 Mermaid 架構圖,直觀對比 <map> 在「記憶體 DOM 樹」與「使用者畫面視覺層」的對應關係:

從上圖可以清楚看出一個極為關鍵的底層特性:
- 視覺像素歸
<img>管:圖片的寬高、載入狀態、濾鏡效果都在<img>節點上。 - 互動事件與無障礙焦點歸
<area>管:當使用者拿滑鼠點擊圖片上的「熱區 A」,或是按鍵盤Tab鍵切換焦點時,瀏覽器觸發的event.target絕對不是<img>,而是位於<map>底下的<area id="zone-a">節點!
三、 實戰代碼教學:從零建構 map 影像地圖與 DOM 事件委派
理解了 <map> 與 DOM 樹的對應邏輯後,我們直接動手寫一個完整的生產級範例:建立一張「伺服器機房架構導覽圖」,包含矩形(rect)、圓形(circle)與多邊形(poly)三種 <area> 熱區,並示範如何利用 DOM 樹的父子關係,在 <map> 上透過 事件委派(Event Delegation) 統一攔截所有熱區點擊!
1. area 三大形狀(shape)與座標(coords)語法規則
圖片的座標原點 (0, 0) 永遠位於圖片的左上角(X 軸向右遞增,Y 軸向下遞增,單位為 CSS 像素):
shape="rect"(矩形):coords="x1,y1,x2,y2"(左上角x1, y1與右下角x2, y2)。shape="circle"(圓形):coords="x,y,r"(圓心座標x, y與半徑r)。shape="poly"(多邊形):coords="x1,y1,x2,y2,x3,y3,..."(依序填入每個頂點的x, y座標,瀏覽器會自動將最後一點與第一點閉合)。
2. 完整 HTML + JavaScript 實戰程式碼
<!-- 檔案名稱:interactive-image-map.html -->
<figure class="architecture-figure">
<!-- 1. 視覺宿主 <img>:必須明確指定原始 width/height,並以 usemap="#名稱" 綁定 -->
<img
src="/images/server-architecture-800x400.png"
alt="雲端系統架構圖:包含 API 閘道器、負載平衡器與主資料庫叢集"
width="800"
height="400"
usemap="#server-arch-map"
id="arch-image"
>
<!-- 2. 熱區容器 <map>:name 屬性不可加 # 號,同時加上同名 id 確保最大相容性 -->
<map name="server-arch-map" id="server-arch-map">
<!-- 矩形熱區:左上角 (40, 80) 到 右下角 (220, 200) -->
<area
shape="rect"
coords="40,80,220,200"
href="#api-gateway"
alt="API Gateway 閘道器模組"
data-component="API Gateway"
data-tps="15,000 req/s"
>
<!-- 圓形熱區:圓心 (400, 140),半徑 65px -->
<area
shape="circle"
coords="400,140,65"
href="#load-balancer"
alt="Nginx 負載平衡器節點"
data-component="Load Balancer"
data-tps="45,000 req/s"
>
<!-- 多邊形熱區:三角形/六邊形資料庫圖示頂點座標 -->
<area
shape="poly"
coords="620,60,740,60,770,140,740,220,620,220,590,140"
href="#primary-db"
alt="PostgreSQL 主從資料庫叢集"
data-component="Primary DB Cluster"
data-tps="8,200 qps"
>
</map>
<figcaption id="status-panel">請點擊上方架構圖中的任一元件檢視即時狀態。</figcaption>
</figure>
<script>
const mapElement = document.getElementById('server-arch-map');
const imgElement = document.getElementById('arch-image');
const statusPanel = document.getElementById('status-panel');
// 🟢 最佳實踐:利用 DOM 樹父子冒泡機制,直接在父容器 <map> 上進行事件委派 (Event Delegation)
mapElement.addEventListener('click', (event) => {
// 確認觸發點擊的 DOM 節點是否為 <area>
const area = event.target.closest('area');
if (!area) return;
event.preventDefault(); // 阻擋預設錨點跳轉,改由 JS 更新面板
console.log('觸發點擊的真實 DOM 節點:', area.tagName);
console.log('該節點在 DOM 樹中的父元素:', area.parentElement.tagName);
console.log('選定元件:', area.dataset.component, '| 吞吐量:', area.dataset.tps);
statusPanel.textContent = `目前選取:${area.dataset.component}(效能指標:${area.dataset.tps})`;
});
// ⚠️ 驗證實驗:如果把 click 綁在 <img> 上,點選 <area> 熱區時根本不會觸發!
imgElement.addEventListener('click', () => {
console.log('你點到了 <img> 上沒有被 <area> 覆蓋的空白背景區域!');
});
</script>
3. 執行結果輸出 (Expected Output)
當使用者點擊圖片中央的「負載平衡器(圓形熱區)」時,Chrome DevTools Console 的輸出如下:
觸發點擊的真實 DOM 節點: AREA
該節點在 DOM 樹中的父元素: MAP
選定元件: Load Balancer | 吞吐量: 45,000 req/s
而如果你點擊圖片上沒有定義 <area> 的空白背景處,Console 才會印出:
你點到了 <img> 上沒有被 <area> 覆蓋的空白背景區域!
四、 新手必踩的 4 大 map 與 DOM 樹實戰地雷
由於 <map> 採用了「視覺在 <img>、節點在 <map>」的分離式架構,前端新手在撰寫語法、綁定事件與處理 RWD 時極易踩中以下四大陷阱:
地雷 1:把點擊事件綁在 img 上,結果點熱區完全沒反應(DOM 事件冒泡路徑誤判)
這是超過 80% 初學者第一次用 JavaScript 控制 Image Map 時會犯的錯誤。新手常以為熱區在圖片上,所以寫 document.querySelector('img').addEventListener('click', ...)。
讓我們用 Mermaid 序列圖看懂瀏覽器內部的 DOM 事件冒泡路徑(Event Bubbling Path):

- 解法:如上方實戰範例所示,請永遠將事件監聽器綁定在
<map>父節點(利用事件委派)或是直接綁定在個別<area>節點上。
地雷 2:usemap 忘記加 # 號,或 map name 誤加 # 號導致綁定完全失效
根據 WHATWG HTML Living Standard (Image Maps),<img> 與 <map> 的配對語法有著嚴格的不對稱規定:
<!-- ❌ 錯誤寫法 1:usemap 漏寫 # 號(瀏覽器完全找不到 map) -->
<img src="map.png" usemap="taiwan" alt="台灣地圖">
<map name="taiwan">...</map>
<!-- ❌ 錯誤寫法 2:把 # 號連同寫進 <map name="#taiwan"> 裡 -->
<img src="map.png" usemap="#taiwan" alt="台灣地圖">
<map name="#taiwan">...</map>
<!-- 🟢 正確寫法:usemap 必加 # 號,map 的 name 與 id 不加 # 號 -->
<img src="map.png" usemap="#taiwan" alt="台灣地圖">
<map name="taiwan" id="taiwan">...</map>
此外請注意:usemap 屬性只能掛在 <img> 標籤上(現代 HTML5 規範已正式移除 <input type="image"> 與 <object> 的 usemap 支援;若使用響應式 <picture> 標籤,usemap 也必須寫在 <picture> 最內層的那個 <img> 上)。
地雷 3:企圖對 area 寫 CSS border 或 background-color 來顯示熱區範圍
許多工程師在除錯座標時,會想寫一行 CSS 把熱區框出來:
/* ❌ 完全無效:瀏覽器根本不會畫出紅色邊框或半透明背景 */
area {
display: block;
border: 2px solid red;
background-color: rgba(255, 0, 0, 0.3);
}
- 底層真相:在瀏覽器的 User Agent 預設樣式表中,
<map>與<area>預設為display: none,它們在 CSS 視覺格式化模型(Visual Formatting Model)中不會產生任何標準的 CSS 矩形盒(Box),因此所有的border、background、box-shadow在<area>上統統無效! - 正確除錯與視覺化方法:
- 在瀏覽器中按
Tab鍵 將鍵盤焦點移至<area>上,瀏覽器原生會沿著coords描繪出對應形狀的 Focus Outline(焦點外框)。 - 若需要在畫面上做出永久的高亮色塊或 Hover 變色效果,現代前端實務會改用 內嵌
<svg>向量圖層(<path>/<polygon>)疊加在圖片上方,或是使用<canvas>繪製。
- 在瀏覽器中按
地雷 4:忽略 area 的 alt 與 href 屬性,導致鍵盤與螢幕閱讀器完全失明
在無障礙網頁(WCAG 2.1 Level A 規範)中,每一個可點擊的 <area> 在無障礙樹(Accessibility Tree)中都等同於一個超連結(role="link"):
- 沒有
href的<area>是死節點:如果<area>漏寫href屬性,它就不會進入鍵盤Tab序列(無法被聚焦),螢幕閱讀器也會直接忽略它。 - 沒有
alt的<area>違反 WCAG 1.1.1:視障者按Tab跳到該熱區時,螢幕閱讀器完全仰賴<area alt="台北分店資訊">來播報該區域的名稱;若漏寫alt,使用者只會聽到冰冷的網址或「連結」。
五、 上線前必查:HTML map 影像地圖 5 點檢驗清單
在將包含 <map> 影像地圖的頁面部署上線前,請逐一核對以下 5 項檢查點:
- ☐ 1.
usemap與name配對語法正確:<img>的usemap="#名稱"是否確認以#開頭?<map>的name="名稱"與id="名稱"是否確認一致且不含#號與空白字元? - ☐ 2. DOM 事件綁定於
<map>或<area>:所有的 JavaScriptclick/mouseenter事件是否都正確綁定在<map>(事件委派)或<area>節點上,而非誤綁在不會收到熱區冒泡的<img>上? - ☐ 3. 每個
<area>皆具備href與精確alt:所有的<area>是否都帶有有效的href與描述該熱區功能的alt替代文字,確保鍵盤Tab鍵能順利聚焦並顯示焦點框? - ☐ 4. 確認原始圖片尺寸與座標基準一致:
<img>的width與height是否與計算coords時所使用的基準尺寸一致?(若頁面支援 RWD 圖片縮放,是否已搭配 JSResizeObserver動態按比例重算coords,或改用<svg viewBox>方案?) - ☐ 5.
<area>宣告順序符合重疊優先權:當兩個<area>熱區座標發生部分重疊時,HTML 解析器遵循「先寫先贏(First-Match Wins)」原則——排在 DOM 樹較前面的<area>會優先攔截點擊,請確認小範圍熱區是否放在大範圍背景熱區之前?
六、 總結與延伸學習
掌握 HTML <map> 與 <area> 標籤,不僅能讓你在處理複雜圖像導覽時免去切圖拼湊的痛苦,更能讓你深刻體會瀏覽器 DOM 樹中「視覺宿主(<img>)」與「邏輯互動節點(<map> > <area>)」分離映射的精妙設計。
當你搞懂了 <map> 的基礎結構與 DOM 事件流向後,接下來在實務開發中還會遇到三個進階挑戰(我們將在後續系列文章中逐一拆解):
- 座標計算實戰:如何快速精準計算
rect、circle、poly的coords像素座標而不翻車? - RWD 響應式縮放:當圖片隨手機螢幕縮小
50%時,如何讓寫死的<area coords>自動等比例跟隨縮放? - 無障礙深度優化:如何處理複雜影像地圖的鍵盤導覽順序與螢幕閱讀器體驗?
七、 參考資料與權威規範延伸閱讀
- WHATWG HTML Living Standard: 4.8.13 The map element & Image maps — W3C/WHATWG 官方最高標準規範,詳列
<map>、<area>的內容模型、usemapHash-name 配對演算法與 Hit-Testing 幾何規則。 - MDN Web Docs:
<map>: The Image Map element — Mozilla 官方開發者指南,完整介紹<map>標籤的屬性規範與瀏覽器相容性。 - MDN Web Docs:
<area>: The Image Map Area element — 深入解析<area>的shape、coords座標格式與alt無障礙必填要求。 - W3C WAI Tutorials: Image Maps — W3C Web Accessibility Initiative 官方影像地圖無障礙實作指南。
發表迴響