使用visibility与:hover切换导航菜单在触控设备上误触发点击
解决SVG触控设备下拉菜单误触发链接问题
我做了一个SVG下拉导航菜单,鼠标悬停时会显示包含相同路径但不同文本的子菜单组,桌面端用鼠标操作一切正常,但在触控设备上,点击会直接触发原本处于visibility: hidden状态的链接。示例代码如下:
<?xml version="1.0" encoding="UTF-8"?> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 306.12 409.2" preserveAspectRatio="none"> <defs> <style type="text/css"> @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600'); .font-md { font-family: 'Poppins'; font-size: 10px; font-weight: 500; } :root { --yellow: #f6b034; } .training { fill: var(--yellow); } .sub-menu { opacity: 0; visibility: hidden; height: 0; } .sub-menu > text { opacity: 0; transition: opacity 0.5s ease-in-out; } .has-dropdown:hover + .sub-menu, .has-dropdown:hover + .sub-menu > text { opacity: 1; visibility: visible; height: auto; pointer-events: auto; transform: unset; } .has-dropdown:hover { opacity: 0; visibility: hidden; height: 0; } .sub-menu:hover { opacity: 1; visibility: visible; height: auto; pointer-events: auto; } .sub-menu:hover > text { opacity: 1; } </style> </defs> <g id="training" class="has-dropdown"> <path class="training" d="m0,256c0-27.61,22.39-50,50-50,27.61,0,50,22.38,50,49.99,0-.21.02-.42.02-.63v29.39c0,11.06,8.45,20.15,19.25,21.15.02,0,.04.09,0,.09-.04,0-62.38,0-69.27,0,0,0,0,0,0,0s0,0,0,0h-.62c.1,0,.21,0,.31,0C22.22,305.82,0,283.51,0,256Z"/> <text style="fill: var(--brown)" class="font-md" transform="translate(31 285)">Training</text> </g> <g id="training-sub-menu" class="sub-menu"> <path class="training" d="m0,256c0-27.61,22.39-50,50-50,27.61,0,50,22.38,50,49.99,0-.21.02-.42.02-.63v29.39c0,11.06,8.45,20.15,19.25,21.15.02,0,.04.09,0,.09-.04,0-62.38,0-69.27,0,0,0,0,0,0,0s0,0,0,0h-.62c.1,0,.21,0,.31,0C22.22,305.82,0,283.51,0,256Z"/> <text style="fill: var(--brown)" class="font-md sub-menu-item" transform="translate(31 285)"> <a href="https://google.com" target="_parent">Google</a> </text> <text style="fill: var(--brown)" class="font-md sub-menu-item" transform="translate(31 265)"> <a href="https://google.com" target="_parent">Google</a> </text> <text style="fill: var(--brown)" class="font-md sub-menu-item" transform="translate(31 245)"> <a href="https://google.com" target="_parent">Google</a> </text> </g> </svg>
问题原因
触控设备的点击行为会同时触发:hover和click事件,即便子菜单设置了visibility: hidden,但默认没有禁用指针事件,导致点击穿透直接触发了隐藏的链接。另外visibility: hidden只是隐藏元素,元素仍占据布局空间,触控点击容易命中该区域下的链接。
解决方案
1. 禁用子菜单默认指针事件
给.sub-menu添加pointer-events: none,默认状态下完全禁用子菜单的交互,只有在hover时再开启:
.sub-menu { opacity: 0; visibility: hidden; height: 0; pointer-events: none; /* 新增 */ }
2. 适配触控设备的伪类
把:hover相关的选择器补充:focus和:active,确保触控点击父元素时优先触发子菜单显示,而非直接触发子链接:
.has-dropdown:hover + .sub-menu, .has-dropdown:focus + .sub-menu, .has-dropdown:active + .sub-menu, .has-dropdown:hover + .sub-menu > text, .has-dropdown:focus + .sub-menu > text, .has-dropdown:active + .sub-menu > text { opacity: 1; visibility: visible; height: auto; pointer-events: auto; transform: unset; } .has-dropdown:hover, .has-dropdown:focus, .has-dropdown:active { opacity: 0; visibility: hidden; height: 0; }
3. 提升可访问性(可选)
给父菜单组添加tabindex="0",让它能响应:focus事件,适配键盘和触控操作:
<g id="training" class="has-dropdown" tabindex="0"> <path class="training" d="m0,256c0-27.61,22.39-50,50-50,27.61,0,50,22.38,50,49.99,0-.21.02-.42.02-.63v29.39c0,11.06,8.45,20.15,19.25,21.15.02,0,.04.09,0,.09-.04,0-62.38,0-69.27,0,0,0,0,0,0,0s0,0,0,0h-.62c.1,0,.21,0,.31,0C22.22,305.82,0,283.51,0,256Z"/> <text style="fill: var(--brown)" class="font-md" transform="translate(31 285)">Training</text> </g>
修改后的完整代码
<?xml version="1.0" encoding="UTF-8"?> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 306.12 409.2" preserveAspectRatio="none"> <defs> <style type="text/css"> @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@500;600'); .font-md { font-family: 'Poppins'; font-size: 10px; font-weight: 500; } :root { --yellow: #f6b034; } .training { fill: var(--yellow); } .sub-menu { opacity: 0; visibility: hidden; height: 0; pointer-events: none; } .sub-menu > text { opacity: 0; transition: opacity 0.5s ease-in-out; } .has-dropdown:hover + .sub-menu, .has-dropdown:focus + .sub-menu, .has-dropdown:active + .sub-menu, .has-dropdown:hover + .sub-menu > text, .has-dropdown:focus + .sub-menu > text, .has-dropdown:active + .sub-menu > text { opacity: 1; visibility: visible; height: auto; pointer-events: auto; transform: unset; } .has-dropdown:hover, .has-dropdown:focus, .has-dropdown:active { opacity: 0; visibility: hidden; height: 0; } .sub-menu:hover { opacity: 1; visibility: visible; height: auto; pointer-events: auto; } .sub-menu:hover > text { opacity: 1; } </style> </defs> <g id="training" class="has-dropdown" tabindex="0"> <path class="training" d="m0,256c0-27.61,22.39-50,50-50,27.61,0,50,22.38,50,49.99,0-.21.02-.42.02-.63v29.39c0,11.06,8.45,20.15,19.25,21.15.02,0,.04.09,0,.09-.04,0-62.38,0-69.27,0,0,0,0,0,0,0s0,0,0,0h-.62c.1,0,.21,0,.31,0C22.22,305.82,0,283.51,0,256Z"/> <text style="fill: var(--brown)" class="font-md" transform="translate(31 285)">Training</text> </g> <g id="training-sub-menu" class="sub-menu"> <path class="training" d="m0,256c0-27.61,22.39-50,50-50,27.61,0,50,22.38,50,49.99,0-.21.02-.42.02-.63v29.39c0,11.06,8.45,20.15,19.25,21.15.02,0,.04.09,0,.09-.04,0-62.38,0-69.27,0,0,0,0,0,0,0s0,0,0,0h-.62c.1,0,.21,0,.31,0C22.22,305.82,0,283.51,0,256Z"/> <text style="fill: var(--brown)" class="font-md sub-menu-item" transform="translate(31 285)"> <a href="https://google.com" target="_parent">Google</a> </text> <text style="fill: var(--brown)" class="font-md sub-menu-item" transform="translate(31 265)"> <a href="https://google.com" target="_parent">Google</a> </text> <text style="fill: var(--brown)" class="font-md sub-menu-item" transform="translate(31 245)"> <a href="https://google.com" target="_parent">Google</a> </text> </g> </svg>
内容的提问来源于stack exchange,提问作者jylesy
相关产品推荐
相关产品推荐

