如何制作与原生title属性样式一致的可悬停、Esc关闭Tooltip
问题描述
我想要复刻原生title属性的Tooltip外观与交互效果,要求:
- Tooltip支持悬停(鼠标移到Tooltip上时不会消失)
- 可通过按Esc键关闭Tooltip
目前我制作的自定义Tooltip无法实现悬停效果,且样式和原生的不一致,附上现有代码寻求帮助:
现有HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="styles.css" /> <title>Tooltip</title> </head> <body> <span class="tooltip-trigger" aria-describedby="tooltip-text" >Hover over me</span > <div id="tooltip-text" class="tooltip-text" role="tooltip"> This is the tooltip text </div> <script src="script.js"></script> </body> </html>
现有CSS代码
.tooltip-text { visibility: hidden; position: absolute; background-color: #000; color: #fff; padding: 4px; z-index: 1; } .tooltip-trigger{ cursor: pointer; } .tooltip-trigger:hover .tooltip-text { visibility: visible; }
现有JS代码
const tooltipTrigger = document.querySelector(".tooltip-trigger"); const tooltipText = document.querySelector(".tooltip-text"); tooltipTrigger.addEventListener("mouseenter", showTooltip); tooltipTrigger.addEventListener("mouseleave", hideTooltip); tooltipText.addEventListener("keydown", dismissTooltip); function showTooltip() { tooltipText.style.visibility = "visible"; } function hideTooltip() { tooltipText.style.visibility = "hidden"; } function dismissTooltip(event) { if (event.keyCode === 27) { tooltipText.style.visibility = "hidden"; } }
解决方案
核心问题拆解
- 悬停失效:Tooltip和触发元素是兄弟节点,鼠标从触发元素移到Tooltip时会触发
mouseleave;同时CSS选择器.tooltip-trigger:hover .tooltip-text不生效,因为Tooltip不是触发元素的子元素。 - 样式不符:原生Tooltip有特定的淡色背景、边框、字体大小和间距,现有样式完全偏离。
- Esc关闭无效:Tooltip默认无焦点,绑定在它身上的
keydown事件无法触发。
修改后的完整代码
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="styles.css" /> <title>Tooltip</title> </head> <body> <!-- 将Tooltip改为触发元素的子元素,保证hover状态延续 --> <span class="tooltip-trigger" aria-describedby="tooltip-text"> Hover over me <div id="tooltip-text" class="tooltip-text" role="tooltip"> This is the tooltip text </div> </span> <script src="script.js"></script> </body> </html>
CSS
/* 完全匹配原生Tooltip样式 */ .tooltip-text { visibility: hidden; position: absolute; background-color: #ffffcc; /* 原生淡黄色背景 */ color: #000; padding: 5px 8px; border: 1px solid #000; /* 原生带黑色细边框 */ border-radius: 3px; font-size: 12px; z-index: 1000; white-space: nowrap; /* 原生不自动换行 */ margin-top: 8px; /* 和触发元素保持原生间距 */ } .tooltip-trigger{ cursor: pointer; position: relative; /* 让Tooltip相对于触发元素定位 */ } /* 触发元素hover显示Tooltip,Tooltip自身hover也保持显示 */ .tooltip-trigger:hover .tooltip-text, .tooltip-text:hover { visibility: visible; }
JS
const tooltipTrigger = document.querySelector(".tooltip-trigger"); const tooltipText = document.querySelector(".tooltip-text"); // 监听全局键盘事件,确保Esc键能触发关闭 document.addEventListener("keydown", dismissTooltip); // 鼠标离开触发元素时,判断是否移到Tooltip上,避免误关闭 tooltipTrigger.addEventListener("mouseleave", function(e) { if (!tooltipText.contains(e.relatedTarget)) { tooltipText.style.visibility = "hidden"; } }); // 鼠标离开Tooltip时关闭 tooltipText.addEventListener("mouseleave", function() { tooltipText.style.visibility = "hidden"; }); function dismissTooltip(event) { // 使用event.key替代已废弃的keyCode,兼容性更好 if (event.key === "Escape") { tooltipText.style.visibility = "hidden"; } }
关键修改说明
- DOM结构调整:把Tooltip嵌套进触发元素内,既让CSS hover选择器生效,也方便相对定位。
- 样式对齐:完全照搬原生Tooltip的背景色、边框、字体和间距,还原原生视觉效果。
- 悬停逻辑修复:通过判断鼠标离开的目标元素,确保移到Tooltip上时不会关闭;同时给Tooltip自身加hover状态兜底。
- Esc功能修复:监听全局键盘事件,确保无论焦点在哪,Esc都能关闭Tooltip,同时用
event.key替代过时的keyCode。
内容的提问来源于stack exchange,提问作者thelonelyCoder
相关产品推荐
相关产品推荐

