area coords 在高 dpr 屏幕上偏移是因为其基于 img.naturalwidth/height 而非 css 渲染尺寸,且不感知 dpr;需按 scalex = offsetwidth/naturalwidth、scaley = offsetheight/naturalheight 分别计算缩放,并依 shape 类型安全重写 coords 字符串。

area coords 为什么在高 DPR 屏幕上会偏移
因为 coords 值永远基于图片原始尺寸(img.naturalWidth/img.naturalHeight),不是 CSS 渲染宽高,更不感知设备像素比(DPR)。哪怕你用 @2x 图片 + max-width: 100%,浏览器也只按缩放后的 offsetWidth 去渲染,而 coords 还是按原始 1200×800 解析——结果就是热区被“压缩”成原尺寸的 1/2 或 1/3,触控完全失准。
缩放比不能只用 window.devicePixelRatio
直接拿 window.devicePixelRatio 去乘 coords 是错的。DPR 描述的是物理像素与逻辑像素的比值,和图片缩放无关。真实缩放比必须从图片自身算:
scaleX = img.offsetWidth / img.naturalWidthscaleY = img.offsetHeight / img.naturalHeight- 两者可能不等(比如
object-fit: cover或宽高比被拉伸)——必须分开计算,不能共用一个 scale - 如果图片未加载完成,
naturalWidth为 0,需等load事件后再执行
如何安全重写 coords 字符串
coords 是纯字符串,不能直接 parseInt 后批量乘——不同 shape 格式语义不同,硬套会把 circle 的半径也缩错,或让 poly 顶点顺序混乱:
-
shape="rect"→ 提取 4 个数:x1,y1,x2,y2,分别乘scaleX, scaleY, scaleX, scaleY -
shape="circle"→ 提取 3 个数:cx,cy,r,前两个乘对应 scale,r必须只乘Math.min(scaleX, scaleY)(保证圆形不压扁) -
shape="poly"→ 每对坐标(x,y)独立缩放:x *= scaleX,y *= scaleY;总数必须保持偶数,否则 Safari 静默跳过 - 所有结果四舍五入为整数:
Math.round(),避免小数导致部分浏览器解析失败
监听 resize 和 load 是必要但不够的
只监听 window.resize 和 img.load 仍会漏掉几种情况:
- 图片被
display: none切换后重新显示,offsetWidth变但没触发 resize - 父容器用
transform: scale()缩放整块区域,img.offsetWidth不变但实际热区已位移 - 动态插入的
img或map,没绑定事件就执行了updateCoords() - 最稳妥做法:每次调用
updateCoords()前先img.offsetParent !== null检查是否可见,再强制getBoundingClientRect()辅助校验
真正难的不是算法本身,而是 coords 一旦写死就彻底脱离上下文——它不继承、不响应、不重绘,只能靠 JS 每次手动“重贴”一遍。别试图用 CSS 或 media query 绕开,规范里它就不是为响应式设计的。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











