鼠标事件 ( pointer-events )
透过 CSS pointer-events 样式属性,可以在元素互相重叠时,穿透上层元素借此点击到下层元素,这篇教学会介绍 CSS pointer-events 样式属性在 SVG 元素与非 SVG 元素的差异,以及如何制作“穿透”的点击或悬停 ( hover ) 效果。
快速导览:
认识 pointer-events
pointer-events 是一个设定“元素是否和鼠标互动,或特定元素与鼠标互动”的样式属性,具有继承特性,最早 pointer-events 是作用于 SVG 元素,让用户可以分别选取位于不同图层的 SVG 内容,后来部分的属性值也支援 HTML 元素,因此也常作用于“穿透”元素的特殊效果。pointer-events 具有下列几种属性值:
| 属性值 | 说明 |
|---|---|
| auto | 默认值,正常与鼠标互动 |
| none | 完全不与鼠标互动 |
| visiblePainted | ( 仅适用 SVG ) 属于 visiblePainted 属性的内容 |
| visibleFill | ( 仅适用 SVG ) 属于 visibleFill 属性的内容 |
| visibleStroke | ( 仅适用 SVG ) 属于 visibleStroke 属性的内容 |
| visible | ( 仅适用 SVG ) 属于 visible 属性的内容 |
| painted | ( 仅适用 SVG ) 属于 painted 属性的内容 |
| fill | ( 仅适用 SVG ) 属于 fill 属性的内容 |
| stroke | ( 仅适用 SVG ) 属于 stroke 属性的内容 |
| all | ( 仅适用 SVG ) 全部 |
非 SVG 元素使用 pointer-events
针对“非 SVG”元素,pointer-events 只能使用 auto 和 none 两个属性值,设定 auto 表示正常的鼠标互动状况,设定 none 则会完全忽略与鼠标的互动,也无法透过 JavaScript 取得相关的鼠标互动事件,下方范例会将写着 banana 的绿色 div 设定为 pointer-events:none,接着就可以在蓝色 div 上触发红色 div 的点击事件或 :hover 改变样式。
<!-- HTML 程式碼 -->
<h3>目前狀態:?</h3>
<div class="a">apple</div>
<div class="b">banana</div>
<div class="c">oxxo</div>
<!-- CSS 程式碼 -->
<style>
div {
position: absolute;
width: 100px;
height: 100px;
border: 1px solid #000;
}
.a {
top: 100px;
left: 100px;
background: #f00c;
}
.a:hover {background: orange;}
.b {
top: 50px;
left: 50px;
background: #0c0c;
pointer-events: none; /* 因為不與滑鼠互動,如果滑鼠移動到 .a .b 交集處,.a 也會變色 */
}
.c {
top: 150px;
left: 150px;
background: #09fc;
}
</style>
<javascript>
let h3 = document.querySelector('h3');
let div = document.querySelectorAll('div');
div.forEach((e)=>{
e.addEventListener('click', function(){
h3.innerHTML = '目前狀態:點擊 ' + e.innerHTML;
});
e.addEventListener('mouseleave', function(){
h3.innerHTML = '目前狀態:?';
});
});
</javascript>
SVG 元素使用 pointer-events
针对“SVG”元素,pointer-events 可以根据不同 SVG 的内容属性,决定该内容要如何与鼠标互动,下方范例会使用两组 SVG,分别设定针对具有 stroke 和 fill 的内容可以侦测鼠标事件,打开网页后将鼠标移动到 SVG 上,就可以发现明显差异。
注意,因为 SVG stroke 会贴齐形状边缘中线,只有在外围没有接触到 fill 才会有互动。
<!-- HTML 程式碼 -->
<div>滑鼠移動到黑色邊框:不會變透明<br/>滑鼠移動到紅色或綠色:會變透明</div>
<svg class="s1">
<g>
<rect x="5.5" y="5.5" fill="#f55" stroke="#0009" stroke-width="20" width="84" height="84"/>
<circle style="fill:#0c0;" cx="95" cy="87" r="54"/>
</g>
</svg>
<div>滑鼠移動到黑色邊框:會變透明<br/>滑鼠移動到紅色或綠色:不會變透明</div>
<svg class="s2">
<rect x="5.5" y="5.5" fill="#f55" stroke="#000" stroke-width="20" width="84" height="84"/>
<circle style="fill:#0c0;" cx="95" cy="87" r="54"/>
</svg>
<!-- CSS 程式碼 -->
<style>
div, svg {margin: 10px;}
svg {width: 200px;}
svg *:hover {opacity: 0.2;}
.s1 {pointer-events: fill;}
.s2 {pointer-events: stroke;}
</style>
小结
除了“穿透”的作用,由于设定了 pointer-events 之后,会连带造成 JavaScript 也无法获得任何鼠标事件,所以一般来说不会特别去使用 pointer-events,但如果是针对一些特殊版面或效果,或许可以透过 pointer-events 轻松实现。
微信扫码关注
抖音扫码关注