定价

Tooltip 使用手册

v1.24.5 · @snowui-design-system/components

许可阅读:首次阅读组件文档、源码或 npm 使用流程,先读完整 LICENSE;同任务同版本去重。公开 API 配置与内部实现修改分别按许可处理;全部组件使用统一运行包,源码权益以许可为准。

组件介绍

在悬停时展示简短说明,支持位置避让与连续切换动效,适合图标按钮和需要补充解释的内容。

使用选择

用于为现有控件提供简短补充提示。主要内容不能只放在 Tooltip;交互表单、菜单或复杂内容优先 Popover / Dialog。

  • 放在触发元素内,不包裹触发器;未提供 children 时读取触发元素文字。

  • open 未传时由 hover 触发;显式 true / false 时由页面控制。主要内容和必要操作不能只藏在提示中。

快速开始

以下示例展示推荐的基本组合。更多场景与组合限制见后文。

<script lang="ts">	import { Tooltip, Button } from '@snowui-design-system/components';</script> <div style="display: flex; align-items: center; gap: var(--gap-4) var(--gap-3); flex-wrap: wrap;">	<Button>		Source		<Tooltip as="tooltip" position="top">Open the component source file on GitHub.</Tooltip>	</Button>	<Button>		Figma		<Tooltip as="tooltip" position="top">Inspect the component and its variants in the SnowUI library.</Tooltip>	</Button>	<Button>		Copy import		<Tooltip as="tooltip" position="top">Copy the public package import statement.</Tooltip>	</Button></div>

API

关键字 类型 默认值 描述
position "top" | "bottom" | "left" | "right" "top" 首选弹出方向;空间不足时按视口安全区自动翻转或平移,以最终方向定位和进入
open boolean — 可绑定的受控显示状态;未传入时使用父级触发器 hover 与共享 Portal,显式 true / false 时由调用方控制独立 Portal,不参与 hover 延迟与速度采样
offset number 4 沿弹出方向与触发器的目标间距,单位 px;最终仍受视口碰撞约束
maxWidth number 360 气泡最大外框宽度(px);仍受当前可视区域四边 16px 安全区限制
variant "dark" | "light" "light" Tooltip 外观变体,默认 light,可显式切换为 dark
dismissOnMotion boolean true 非受控 hover 模式下,触发元素或其祖先开始动效,或后代开始几何 transition 时立即隐藏 Tooltip;后代装饰性 animation 与 Button 内容整体缩放不关闭,后者不改变触发器锚点
widthRebound boolean false 连续切换时是否为外框宽度启用越界回弹;默认关闭,开启后宽度会越过目标再回弹
rapidRetarget boolean true 连续动效进行中再次切换目标时,是否选用 90–160ms cubic ease-out 快速基线;关闭后选用普通 120–180ms 协调基线;两者均可根据有效鼠标速度缩短至最低 60ms
children Snippet — 提示内容,无参数;支持文本或公开组件组合。不提供时读取父级触发元素的文本;Tooltip 本身不包裹触发器,而是放在触发元素内

未重新声明的继承能力请查所属基础组件文档;本表只列本组件源码具名公开属性。

使用边界与详细说明

关键字 (Keyword)

关键字 类型 默认值 描述
as 'tooltip' - 角色化:作为父组件的提示层

使用示例

 <Icon icon={Info} >    <Tooltip as="tooltip">更多信息</Tooltip></Icon>  <Button>    Hover    <Tooltip open={showTip}>提示内容</Tooltip></Button>  <Text lines={1}>    这是一段会被截断的文本    <Tooltip as="tooltip" /></Text>

布局模型

主布局模型:内联外壳布局。定义见 ../../../specs/maintainers/LayoutProtocol.md §12.4(源码参考:specs/maintainers/LayoutProtocol.md)。

Tooltip 的 Portal、定位、碰撞翻转属于组件行为;可见气泡内容本身按内联外壳布局管理:

  • .snowui-tooltip-content 是 inline-level 外壳,内容整体 Hug。

  • 子内容通过 gap 自然排列,不提供 Content Fill。

  • 气泡自身负责 padding / gap / radius / font-size / line-height,并通过 --snowui-tooltip-*-override 变量允许外部覆盖。

  • 短内容保持 Hug;长内容先按最大宽度换行,再统一测量并选择方向,避免位置与换行互相反馈。长单词和 URL 允许断行。

  • 内容支持鼠标移入保留显示;超高内容限制到安全区高度并内部滚动,移出后沿用共享隐藏延迟。

布局变量链:

变量 默认来源 用途
--snowui-tooltip-padding var(--padding-1) var(--padding-2) 气泡内边距
--snowui-tooltip-gap var(--gap-2) 子内容间距
--snowui-tooltip-radius var(--radius-3) 气泡圆角
--snowui-tooltip-font-size var(--text-12) 提示文字字号
--snowui-tooltip-line-height var(--leading-12) 提示文字行高

智能行为

  1. hover 延迟: 首次 hover 延迟 450ms 显示;Tooltip 成功显示后,在 300ms cooldown 窗口内进入其他 Tooltip 时立即切换,不增加固定意图延迟。

  2. 共享外框: 非受控 hover 模式始终复用页面级 Portal。离开当前触发器后的外框保留窗口与 300ms skip-delay 一致;窗口内进入另一个 Tooltip 时取消隐藏,不重新播放出现动效。warm 切换的新内容提交后立即读取一次真实 Snippet 尺寸并定位,连续时间线在首个可用绘制帧进入 moving;后续内容尺寸变化仍由共享 ResizeObserver 合帧处理。

  3. 二维连续切换: 仅当共享外框仍可见且切换到另一个触发器时执行。以气泡外框中心计算位移;中心距离不超过 240px,且 hypot(dx / 可视宽度, dy / 可视高度) ≤ 0.25 时,外框沿任意二维向量移动并同步改变宽高;超过阈值时直接定位。鼠标速度适配规则见下文第 11 项;以下为未提速时的基线。普通近距离位置与内容时间线为 clamp(100ms + distance × 0.35ms/px, 120ms, 180ms) cubic ease-out 协调曲线。默认 rapidRetarget=true;只有位置与内容交接尚未结束时再次改目标,才从当前可见画面接管并改用 clamp(60ms + distance × 0.35ms/px, 90ms, 160ms) cubic ease-out 和 0.02 内容滞后。设为 false 时,中断仍使用普通协调时间线和 0.02 内容滞后。默认 widthRebound=false,宽度跟随当前所选位置时间线直接收敛;显式设置 widthRebound=true 时,宽度独立使用 1000ms 欠阻尼弹簧,不被快速重定向缩短。位置与内容已完成、仅剩宽度回弹尾段时,新目标必须启动完整的普通内容交接,不得因宽度仍在回弹而压缩裁切揭示。两种模式都从当前可见宽度为新起点,不继承累计速度。top / bottom 以中心、left 以右边、right 以左边保持触发器侧锚点。具体值以 Tooltip continuous preset 为准。

  4. 内容带拼接与协调时间线: 新旧目标 Tooltip 矩形最短距离不超过 4px 时,旧、新内容沿外框移动向量拼成投影间距为 16px 的内容带。测量边界是完整 Snippet 的 .snowui-tooltip-inner。外框位置与内容移动同帧开始,并在当前速度适配后的有界时程内完成对齐;旧内容层保留至宽度弹簧首次回弹点 450ms。旧层清理只卸载 outgoing,不重置 incoming 偏移;incoming 继续按当前外框宽度补偿位置,直到宽度弹簧精确收敛,避免清理帧文字瞬间归零后又恢复造成抖动。运动中改目标时,以裁切窗口内实际可见面积更大的内容层接管,并在同一帧冻结实时视口矩形。圆角外框是唯一裁切窗口;距离超过 4px 时不拼接、不保留旧内容,但新内容必须在过渡中的外框内按最终 placement 保持局部对齐:top / bottom 水平居中,left 靠右,right 靠左;垂直方向 top 靠下、bottom 靠上、left / right 居中。

  5. 重新出现规则: 外框已经隐藏后,不论间隔多久再次 hover,都重置上一次的坐标、尺寸和触发器记录;新一轮 Tooltip 首帧先完成不可见测量和定位,再直接从当前 hover 位置出现,不做位移动效和宽度变化动效。

  6. 冷却恢复: 离开 Tooltip 触发器超过 300ms 后,恢复首次 hover 的 450ms 延迟。未成功显示就移开时,不进入立即显示模式。

  7. 边界碰撞: 使用当前文档的 visualViewport(不可用时使用 window),iframe 内以 iframe 可视区为界。四边保留 16px;先限制外框宽度到 min(maxWidth, 可视宽度 − 32px),高度到可视高度 − 32px,再测量。依次尝试指定方向、反方向、其余两个方向,每个方向先沿交叉轴平移;优先完整落入安全区的位置,否则选择总溢出距离最小的位置并沿两轴移回安全区。窗口缩放、滚动、软键盘和内容尺寸变化均重新计算。连续切换(包括显式宽度回弹)也按安全区限制宽度和位置。Escape 关闭当前提示。安全区小于内容内边距的极小视口无法保证 16px。

  8. 动效感知关闭: 默认只在 Tooltip 已显示期间,以页面级单例监听触发元素与祖先的 transition / animation,以及后代真实元素的几何 transition;命中后立即卸载 Tooltip 并跳过退出动效。Button 已登记内容层的整体 transform 不改变触发器锚点,因此不触发关闭;其他后代几何过渡仍遵循原规则。后代 Logo / Icon 等装饰性 animation、颜色、背景、透明度以及 ::before / ::after 伪元素 transition 不触发关闭;可通过 dismissOnMotion={false} 显式关闭。

  9. 连续打断与性能: 位置或内容交接未结束又切换目标时,从当前外框和主要可见内容层的实时矩形重新计算下一段移动;旧时间线立即作废,不排队、不等待,也不得先跳到上一段终点。rapidRetarget 默认开启并使用 90–160ms cubic ease-out;关闭后使用普通 120–180ms cubic ease-out 协调曲线。独立宽度回弹的尾段不属于快速重定向窗口;此时切换目标使用完整普通内容时间线,同时宽度从当前可见值重新响应。warm 目标不得在内容已提交后再额外等待一个定位 rAF 和一个启动 rAF;切换专用同步测量只执行一次,不新增 Observer 或逐帧测量。合成提示只在 moving 阶段使用 will-change。

  10. 触发与减少动态效果: warm Tooltip 的每次目标变化都立即提交,不用固定意图延迟或 burst 窗口决定是否播放连续裁切;平滑指针速度只调整时长,不跳过连续裁切。prefers-reduced-motion: reduce 下,所有连续切换都立即定位并只显示新内容,不保留移动、宽高过渡或中间裁切状态。

  11. 鼠标速度自适应: 有效鼠标速度只缩短所选基线时程:min(基线时长, max(60ms, 外框中心距离 / 平滑速度 + 20ms)),速度单位为 px/ms。采用 32ms 指数平滑,超过 100ms 未采样则失效;慢移或无有效样本时保留距离基线。每次目标切换只读取一次速度,外框位置、高度、默认宽度与内容共用该时长;不在段内反复变速,速度适配不改变所选曲线和内容滞后,也不缩短显式 1000ms 宽度回弹。采样只在共享 Tooltip 活动且允许平滑动效时开启,只有一个被动监听;隐藏、卸载与 reduced-motion 时释放。首次 hover 延迟与受控 open 不受影响。

  12. 交互宿主解析: Tooltip 直接放在 Link / Button 的内部包装层时,以最近的 a / button / role="link" / role="button" 祖先作为 hover 命中与定位触发器;无交互祖先时保持以 Tooltip 的直接父元素为触发器。因此组件内部 label 在折叠态变为零宽或隐藏时,可见主操作仍保留完整 Tooltip 命中区。

  13. 多实例性能边界: 非受控 Tooltip 实例只保留各自触发器的 enter / leave 监听。页面级 Overlay store 响应、动效关闭注册、prefers-reduced-motion 查询和 window scroll / resize 定位监听只由唯一共享 Portal host 承担;只有当前可见的受控 Tooltip 会额外注册自身定位监听。scroll、resize 与尺寸测量引起的重复定位请求通过 requestAnimationFrame 合并,每帧最多执行一次布局读取。

  14. 内容所有权: 共享外框只在来源组件存活期间借用其内容Snippet。来源卸载时立即释放对应当前/旧层内容,不为退出动画继续读取已销毁来源;仅旧层来源卸载时,结束该段交接并保留存活目标。普通鼠标离开仍沿用原隐藏延迟及退出动画。

1) 气泡基础布局

  • 渲染层通过 Portal 挂载到 document.body,定位方式为 position: fixed。

  • 内容容器使用 inline-flex,并固定 align-items: center、justify-content: flex-start。

  • 内容层可悬停;移入取消隐藏计时,移出恢复隐藏计时。

  • 层级固定为 z-index: 9999,正文使用 white-space: normal 和 overflow-wrap: anywhere。

2) Figma Token 映射

  • padding: --snowui-tooltip-padding → var(--padding-1) var(--padding-2)(上下 4,左右 8)

  • gap: --snowui-tooltip-gap → var(--gap-2)(8)

  • border-radius: --snowui-tooltip-radius → var(--radius-3)(12)

  • font-size/line-height: --snowui-tooltip-font-size / --snowui-tooltip-line-height → var(--text-12) / var(--leading-12)

3) 视觉主题

  • variant="dark"(通过 data-variant 驱动):

    • 背景:Static Black/80% + Static White/10% 叠加

    • 文字:Static White/100%

  • 默认 variant="light":

    • 背景:Black/4%

    • 文字:Black/100%

4) 滤镜与阴影

  • Backdrop 保留完全透明的渐变绘制面,避免浏览器省略无背景绘制层的滤镜合成;颜色与生命周期动效仍由 Foreground 持有。

  • 保留毛玻璃:backdrop-filter: blur(1.25rem)(含 -webkit-backdrop-filter)。

  • Portal 必须保持在应用根节点隔离层之外,且自身不得被全局根节点选择器误加 isolation: isolate;否则毛玻璃虽有计算值,但无法采样应用根节点内的页面内容。根节点隔离规则见 StyleSpec.md §2.6.4(源码参考:specs/maintainers/StyleSpec.md)。

  • 当前版本已移除阴影,不使用 box-shadow。

5) 显隐与连续切换动效

  • 非受控模式(open 未传入)下:

    • 首次鼠标进入触发器后延迟 450ms 显示,显示成功后的 skip-delay 为 300ms;

    • 自动根据视口边缘做碰撞翻转;

    • Tooltip 成功显示后,页面内其他 Tooltip 在 300ms cooldown 窗口内立即响应;每个目标都从当前画面重定向连续裁切,旧时间线立即作废,不累积多段慢动效;

    • 连续切换触发器时复用同一个 Portal 外框;近距离切换沿任意二维方向移动,远距离切换直接定位;

    • 连续移动使用独立的 transform wrapper 承接位置变化,Portal 锚点仍按现有定位语义更新;宽高由同一逐帧几何时间线更新;

    • 新旧目标 Tooltip 矩形最短距离不超过 4px 时,旧、新内容沿实际二维移动向量拼成投影间距为 16px 的内容带;切换使用速度适配后的普通 / 快速有界协调时间线;snowui-tooltip-size-shell 的 overflow: hidden 与圆角共同形成唯一揭示边界;

    • 新旧目标 Tooltip 矩形最短距离超过 4px 时,不拼接、不保留旧内容;新内容按最终 placement 在当前外框内保持局部对齐并随外框一起移动,不能在长内容切短内容时默认贴住左上角;

    • 动画中断时读取外框和当前内容层的实时矩形,再以各自当前可见位置作为下一段起点;

    • 新一轮显示先完成不可见测量和定位,并为毛玻璃层保留一个不可见预绘制帧,再整体显示 Portal;稳定 Backdrop 首帧以完整 opacity 提供 blur,独立 Foreground 通过 getTooltipAppearMotion(finalPosition) 执行 opacity、增强 scale 和 placement 定向滑入。top 从下向上、bottom 从上向下、left 从右向左、right 从左向右;具体数值以 Tooltip preset catalog 为准。Portal 与 Backdrop 不参与该出现动效,因此渐显不会削弱滤镜;

    • 外框隐藏后再次出现时重置运动基线,首帧直接定位到当前触发器,并在渐显结束后才开启后续尺寸动效;

    • 离开触发器超过 300ms 后恢复 450ms 首次延迟;

    • 生命周期出现只在 snowui-tooltip-foreground 使用 Tooltip appear preset 的显式 opacity / scale / x / y 通道;transform origin 固定在靠近触发器的一侧中心,后续尺寸变化继续由 Frame Idle -> Active 形态时序承接;

    • 内容宽高变化由 snowui-tooltip-size-shell 保存明确宽高。普通尺寸变化继续消费 Frame size motion bridge;连续切换默认使用与外框位置相同的逐帧协调时间线并单调收敛,widthRebound 显式开启时才由独立宽度弹簧产生轻微越界回弹。圆角和 padding 归 size shell,毛玻璃归稳定 Backdrop,背景色和内容归 Foreground;三个层级共享同一尺寸与裁切边界;

    • top / bottom 方向使用触发器中心作为固定锚点,尺寸外壳用静态 transform: translateX(-50%) 保持居中;left / right 方向使用触发器垂直中心作为固定锚点,尺寸外壳用静态 transform: translateY(-50%) 保持居中;宽高由 Frame size motion bridge 过渡,但居中偏移不参与过渡,因此连续切换和尺寸变化过程中 Tooltip 仍保持与触发器居中对齐;

    • 鼠标移开后按 300ms skip-delay 保留外框以承接相邻触发器切换;窗口内命中新 Tooltip 时取消隐藏并直接复用。超过窗口仍未命中时把 Foreground Frame 切到 Disappear 状态,使用参考 transitions.dev Tooltip 的 50ms 退出动效:背景色和内容淡出并缩到 98%;退出完成后再卸载包含 Backdrop 的共享外框。

    • prefers-reduced-motion: reduce 下关闭位置、宽高和内容带过渡,并同步清理旧内容层。

  • 受控模式(open 传入)由外部状态直接控制显隐,不参与共享 warmup / cooldown 状态。

  • 当外部传入 loopMotion.preset="rotateClockwise" 等循环默认能力时,Portal 外层 Frame 会直接承接该动效;因此 Tooltip 可见浮层本身可以连续旋转,且不会覆盖内部内容层的 appear transform。



Tooltip 样式覆盖

先阅读 完整 LICENSE;同任务、同版本、同范围去重。

优先用组件公开 Props 匹配合适样式,尽可能保留原有视觉。确需改写时按 样式选择与改写顺序 使用自己的 class(含项目已有 Tailwind)或实例 style。以下名称来自源码实际消费的公开 override;先核对目标作用域,不修改私有 DOM。采用 SnowUI Token 时选择正确类别,外部应用不被要求安装一方 utilities。

变量 用途与默认参考
--snowui-tooltip-font-size-override font-size(默认值见组件源码)
--snowui-tooltip-gap-override gap(默认 var(--gap-2) = 8px)
--snowui-tooltip-left-override left 偏移(默认值见组件源码)
--snowui-tooltip-line-height-override line-height(默认值见组件源码)
--snowui-tooltip-padding-override padding y+x(默认 4px 8px)
--snowui-tooltip-radius-override border-radius(默认 var(--radius-3) = 12px)
--snowui-tooltip-top-override top 偏移(默认值见组件源码)

设计指南 · Token · 组合边界

Tooltip 类型与状态

必填属性:无具名必填属性。

可双向绑定:bind:open。

继承声明:FrameProps。继承能力以基类公开文档为准;Omit 中的字段已排除,不能按基类原样使用。

共享 Frame API · 返回 API

以下为公开属性实际引用的类型声明,来自源码;Svelte Snippet 表示内容片段,ComponentProps 表示对应组件的 Props。