coords 坐标基于图像原始尺寸计算,不随缩放变化,因此需按渲染宽高与自然宽高的比例动态重算;错误做法包括写死像素、使用 transform 或 zoom;推荐方案为监听 resize 和 load 事件,用 scalex/scaley 分别缩放 coords,并添加防抖。

area 标签的 coords 坐标不会随图片缩放自动适配,写死的像素值在 img 使用 width、height 或 CSS 缩放后必然偏移——这不是 bug,是规范行为。
为什么 coords 在缩放后全都不准
coords 始终基于图像原始尺寸(img.naturalWidth/naturalHeight)计算,和渲染尺寸无关。比如原图 1200×800,你在 PS 里量出按钮区域是 (300,150)-(500,250),那 coords="300,150,500,250" 才对;哪怕 <img style="max-width:90%"> 把它压成四分之一,浏览器仍按 1200×800 映射这组坐标。
常见错误现象包括:鼠标悬停无反应、焦点跳到别处、屏幕阅读器读不到对应区域、手机上热区整体右下偏移。
- 用
getBoundingClientRect().width直接读取当前渲染宽度,再按比例换算coords—— 这是唯一可靠的手动重算路径 - 不要试图用 CSS
transform: scale()或zoom处理图片,它们会破坏area的坐标映射逻辑 -
shape="poly"的顶点顺序错一位,整个多边形就可能翻转或塌陷,务必校验偶数个数字且成对
用 JavaScript 动态重算 coords 的最小可行方案
监听 resize 和 img.onload,拿到当前渲染尺寸后线性缩放原始 coords 值:
function recalcCoords() {
const img = document.getElementById('map-img');
const map = document.querySelector('map[name="legenda"]');
const areas = map.querySelectorAll('area');
const rect = img.getBoundingClientRect();
const scaleX = rect.width / img.naturalWidth;
const scaleY = rect.height / img.naturalHeight;
<p>areas.forEach(area => {
const coords = area.coords.split(',').map(Number);
const newCoords = coords.map((v, i) =>
i % 2 === 0 ? Math.round(v <em> scaleX) : Math.round(v </em> scaleY)
);
area.coords = newCoords.join(',');
});
}</p><p>window.addEventListener('resize', recalcCoords);
document.getElementById('map-img').addEventListener('load', recalcCoords);
</p>
注意:scaleX/scaleY 必须分开计算,响应式缩放常是非等比的(如 width: 100%; height: auto);防抖不是可选,而是必须——拖拽窗口时高频触发,不加 setTimeout 容易卡死。
更彻底的替代方案:什么时候该放弃 area
当页面需要强响应式、多设备适配、或热区形状复杂(如带圆角、贝塞尔曲线),硬扛 area 是低效选择。
-
<svg></svg>是首选:每个<path></path>可设role="link"+aria-label,坐标系天然响应式,缩放不丢精度 - 第三方库如
imagemapster能自动绑定事件并重算,但需额外加载、且对现代构建工具支持弱 - 纯 CSS 方案(
position: absolute+ 伪元素覆盖)只适用于简单矩形,无法处理多边形或无障碍需求
真正容易被忽略的是:所有 <area> 的 alt 文本必须语义明确,不能写“点击此处”或复用图片 alt;而 <map></map> 元素在 DOM 中必须出现在对应 <img> 后方或同级——JS 动态插入时若晚于图片渲染,部分屏幕阅读器会直接跳过整张图的热区。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











