title属性最简单但限制多:仅纯文本、1秒延迟、移动端不可靠、不支持交互与无障碍;推荐aria-describedby+隐藏元素方案,或css data-tooltip免js方案,复杂场景应使用radix ui等成熟库。

用 title 属性最简单,但有严重限制
直接在任意 HTML 元素上加 title 属性,浏览器会自动显示原生工具提示。比如:<button title="保存当前设置">保存</button>。但它只支持纯文本,不支持换行、样式、图标或交互;鼠标移入延迟约 1 秒,且无法用 CSS 定制外观;在移动端几乎不可靠(iOS Safari 基本不触发)。
常见错误是以为 title 能替代自定义弹层——它不能响应点击、不支持键盘焦点、无法适配高对比度模式,WCAG 也不推荐依赖它做关键提示。
需要样式/交互?用 aria-describedby + 隐藏元素
这是兼顾可访问性和可控性的主流做法:先写一个带 id 的隐藏提示元素,再用 aria-describedby 关联到目标控件。
<button aria-describedby="hint-1">上传</button><br><div id="hint-1" class="tooltip" style="display:none;">支持 JPG/PNG,最大 5MB</div>
立即学习“前端免费学习笔记(深入)”;
要点:
- 隐藏提示元素必须用
display: none或visibility: hidden,不能仅靠opacity: 0(屏幕阅读器仍可能读取) -
aria-describedby的值必须严格匹配提示元素的id,大小写敏感 - 需配合 JS 控制显隐逻辑(如 hover/focus 时
display: block),否则用户看不到 - 务必加
role="tooltip"到提示容器,辅助技术才能正确识别语义
现代方案:CSS :hover + data-* 属性免 JS
如果只需求基础悬停提示,且不强依赖无障碍,纯 CSS 更轻量。核心是利用 data-tooltip 存文本,:hover::after 渲染浮层。
<span data-tooltip="已复制到剪贴板">复制链接</span>
CSS 示例:
span[data-tooltip] { position: relative; }<br>span[data-tooltip]:hover::after {<br> content: attr(data-tooltip);<br> position: absolute; top: -30px; left: 50%;<br> transform: translateX(-50%);<br> background: #333; color: #fff; padding: 4px 8px;<br> border-radius: 4px; font-size: 12px;<br>}
注意点:
- 移动端无效(无 hover),需额外加
focus或点击逻辑 - 内容过长会溢出,建议限制
max-width和强制换行 - 绝对定位容易被父容器
overflow: hidden截断,要检查层级和裁剪
React/Vue 等框架里别手写 tooltip 组件
直接用成熟库更稳,比如 React 的 @radix-ui/react-tooltip 或 Vue 的 v-tooltip。它们已处理好焦点管理、键盘导航(Tab/Escape)、延迟控制、边界检测、SSR 兼容等细节。
自己实现容易漏掉:
- 失焦后 tooltip 不自动关闭(尤其表单内)
- Tooltip 遮挡操作区域,又没提供
offset或side配置 - 服务端渲染时 JS 未加载导致首次无提示
- 没有
delayDuration或skipDelayDuration控制悬停响应节奏
真正难的不是显示文字,是让提示在各种上下文里“不碍事、不消失、不误导”。这点连 Chrome 自带的 title 都没完全做到。











