area 标签不支持 :hover 伪类,因其无盒模型、不可见、不触发鼠标事件;需用绝对定位 div 模拟区域并结合 pointer-events 分层实现悬停效果。

area 标签本身不支持 :hover,任何直接写 area:hover { background: ... } 的 CSS 都不会生效——这不是你写错了,而是浏览器根本不会渲染 area 为可视节点,它没有盒模型、不能定位、无法触发伪类样式。
为什么 area 不能用 :hover
area 是纯语义化坐标映射元素,只在 map 内部起作用,DOM 中不可见、无尺寸、无层级。DevTools 里看不到它,getBoundingClientRect() 返回 { width: 0, height: 0 },mouseenter 事件也**不会冒泡到它身上**。所以所有基于视觉反馈的 hover 效果(GIF、背景图、颜色变化)必须绕开它做。
用绝对定位 div 模拟可 hover 区域
核心思路:保留原 img + map 的点击逻辑,另起一层带坐标的透明容器,覆盖在对应区域上。
- 从
area.coords解析出x1,y1,x2,y2(注意:不是所有浏览器都支持coords属性直接读取,建议写死或用 JS 提前计算) - 用
position: absolute的div覆盖该矩形区域,设pointer-events: none保证底层area点击仍有效 - 再套一层
pointer-events: auto的子容器,专门响应:hover并显示 GIF 或其他效果 - 务必设置
z-index和父容器position: relative,否则定位会脱标
<div class="map-container">
<img src="map.png" usemap="#main-map" alt="interactive map">
<map name="main-map">
<area shape="rect" coords="100,50,200,120" href="#" alt="zone-a">
</map>
<!-- 悬停层 -->
<div class="area-overlay" style="left:100px;top:50px;width:100px;height:70px;">
<div class="hover-trigger"></div>
</div>
</div>对应 CSS:
立即学习“前端免费学习笔记(深入)”;
.map-container { position: relative; display: inline-block; }
.area-overlay { position: absolute; pointer-events: none; }
.area-overlay .hover-trigger {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
pointer-events: auto;
background: transparent;
}
.area-overlay .hover-trigger:hover {
background: url("hover-effect.gif") no-repeat center center;
background-size: contain;
}用 JavaScript 绑定 mouseenter/mouseleave 替代 CSS hover
当需要动态切换图片、播放动画或触发动态内容时,JS 更可控,且能兼容非矩形区域(如 shape="poly")。
- 不要监听
area自身事件——它不派发mouseenter - 监听整个
img的mousemove,结合event.offsetX/Y和预定义的区域坐标判断是否进入 - 或更简单:给每个
area加data-id,用 jQuery 的.on('mouseenter', '[data-id]')——但注意这其实是监听了map的事件委托,实际依赖的是浏览器对area的隐式事件转发(部分旧浏览器不支持) - 推荐方案:用
IntersectionObserver+canvas坐标判定,适合复杂多边形,但开销略高
简例(矩形区域):
const img = document.querySelector('.main-map-img');
const zones = [
{ id: 'a', x1: 100, y1: 50, x2: 200, y2: 120, gif: 'a.gif' }
];
<p>img.addEventListener('mousemove', (e) => {
const rect = img.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;</p><p>for (const zone of zones) {
if (x >= zone.x1 && x <= zone.x2 && y >= zone.y1 && y <= zone.y2) {
document.body.style.backgroundImage = <code>url(${zone.gif})</code>;
return;
}
}
document.body.style.backgroundImage = 'none';
});常见坑与性能提醒
最容易被忽略的是坐标系错位和缩放适配:
-
area.coords基于原始图片尺寸,若img用了width/height或max-width缩放,坐标必须按比例换算,否则悬停层会偏移 - 响应式页面中,窗口 resize 后需重新计算 overlay 尺寸和位置,别忘了加
window.addEventListener('resize', updateOverlays) - GIF 悬停频繁加载会导致内存泄漏,建议预加载所有 GIF 到
new Image().src = url,或用 CSSanimation+sprite替代 - 移动端没有 hover,
touchstart和touchend需单独处理,且 iOS Safari 对pointer-events支持不稳定
真正麻烦的从来不是“怎么让 hover 动起来”,而是“怎么让它在不同尺寸、不同设备、不同缩放下始终精准贴合区域”。坐标映射一旦错一位,用户就点不到,也 hover 不到——这点比写十个动画都关键。



















