Skip to content

Tooltip 工具提示

实时预览

引入

html
<link rel="stylesheet" href="/tokens/tokens.css">
<link rel="stylesheet" href="/components/tooltip/tooltip.css">

代码

HTML

html
<!-- Tooltip Component — 工具提示组件,支持 top、bottom、left、right 四种方向 -->


<!-- Demo: Tooltip 组件 -->
<div style="display: flex; flex-direction: column; gap: 48px; padding: 40px; max-width: 600px;">
  <!-- 方向变体 -->
  <div>
    <h4 style="margin: 0 0 24px 0; font-size: var(--text-sm); color: var(--color-text-secondary);">方向变体</h4>
    <div style="display: flex; justify-content: space-around; align-items: center; height: 200px;">
      <!-- 顶部 -->
      <div class="tooltip tooltip--top">
        <button class="tooltip__trigger btn btn--primary btn--md">顶部</button>
        <div class="tooltip__content">这是顶部的工具提示</div>
      </div>
      
      <!-- 底部 -->
      <div class="tooltip tooltip--bottom">
        <button class="tooltip__trigger btn btn--primary btn--md">底部</button>
        <div class="tooltip__content">这是底部的工具提示</div>
      </div>
      
      <!-- 左侧 -->
      <div class="tooltip tooltip--left">
        <button class="tooltip__trigger btn btn--primary btn--md">左侧</button>
        <div class="tooltip__content">这是左侧的工具提示</div>
      </div>
      
      <!-- 右侧 -->
      <div class="tooltip tooltip--right">
        <button class="tooltip__trigger btn btn--primary btn--md">右侧</button>
        <div class="tooltip__content">这是右侧的工具提示</div>
      </div>
    </div>
  </div>

  <!-- 颜色变体 -->
  <div>
    <h4 style="margin: 0 0 24px 0; font-size: var(--text-sm); color: var(--color-text-secondary);">颜色变体</h4>
    <div style="display: flex; gap: 24px; align-items: center;">
      <!-- 成功 -->
      <div class="tooltip tooltip--top tooltip--success">
        <button class="tooltip__trigger btn btn--secondary btn--md">成功</button>
        <div class="tooltip__content">操作成功!</div>
      </div>
      
      <!-- 警告 -->
      <div class="tooltip tooltip--top tooltip--warning">
        <button class="tooltip__trigger btn btn--secondary btn--md">警告</button>
        <div class="tooltip__content">请注意此操作</div>
      </div>
      
      <!-- 危险 -->
      <div class="tooltip tooltip--top tooltip--danger">
        <button class="tooltip__trigger btn btn--secondary btn--md">危险</button>
        <div class="tooltip__content">此操作不可撤销</div>
      </div>
    </div>
  </div>

  <!-- 不同触发元素 -->
  <div>
    <h4 style="margin: 0 0 24px 0; font-size: var(--text-sm); color: var(--color-text-secondary);">不同触发元素</h4>
    <div style="display: flex; gap: 24px; align-items: center;">
      <!-- 图标按钮 -->
      <div class="tooltip tooltip--top">
        <button class="tooltip__trigger btn btn--ghost btn--md">
          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
            <circle cx="12" cy="12" r="10"></circle>
            <path d="M12 16v-4"></path>
            <path d="M12 8h.01"></path>
          </svg>
        </button>
        <div class="tooltip__content">更多信息</div>
      </div>
      
      <!-- 文本链接 -->
      <div class="tooltip tooltip--top">
        <a href="#" class="tooltip__trigger" style="color: var(--color-primary); text-decoration: underline;">
          悬停查看提示
        </a>
        <div class="tooltip__content">这是一个文本链接的工具提示</div>
      </div>
      
      <!-- 图片 -->
      <div class="tooltip tooltip--top">
        <div class="tooltip__trigger" style="width: 40px; height: 40px; background: var(--color-primary); border-radius: var(--radius-full); display: flex; align-items: center; justify-content: center; color: white; font-weight: bold;">
          ?
        </div>
        <div class="tooltip__content">点击获取帮助</div>
      </div>
    </div>
  </div>

  <!-- 禁用状态 -->
  <div>
    <h4 style="margin: 0 0 24px 0; font-size: var(--text-sm); color: var(--color-text-secondary);">禁用状态</h4>
    <div class="tooltip tooltip--top tooltip--disabled">
      <button class="tooltip__trigger btn btn--ghost btn--md" disabled style="opacity: 0.5; cursor: not-allowed;">
        禁用按钮
      </button>
      <div class="tooltip__content">这个提示不会显示</div>
    </div>
  </div>
</div>

<!-- 按钮样式(用于演示) -->


<script>
// Tooltip 交互逻辑
document.addEventListener('DOMContentLoaded', function() {
  // 为所有工具提示添加键盘支持
  const tooltips = document.querySelectorAll('.tooltip');
  
  tooltips.forEach(tooltip => {
    const trigger = tooltip.querySelector('.tooltip__trigger');
    const content = tooltip.querySelector('.tooltip__content');
    
    if (!trigger || !content) return;
    
    // 添加 tabindex 使元素可聚焦
    if (!trigger.hasAttribute('tabindex')) {
      trigger.setAttribute('tabindex', '0');
    }
    
    // 键盘事件
    trigger.addEventListener('keydown', function(e) {
      if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        // 切换工具提示显示状态
        const isVisible = content.style.opacity === '1';
        content.style.opacity = isVisible ? '0' : '1';
        content.style.visibility = isVisible ? 'hidden' : 'visible';
      }
      
      if (e.key === 'Escape') {
        content.style.opacity = '0';
        content.style.visibility = 'hidden';
      }
    });
    
    // 焦点事件
    trigger.addEventListener('focus', function() {
      if (!tooltip.classList.contains('tooltip--disabled')) {
        content.style.opacity = '1';
        content.style.visibility = 'visible';
      }
    });
    
    trigger.addEventListener('blur', function() {
      content.style.opacity = '0';
      content.style.visibility = 'hidden';
    });
  });
  
  // 点击外部关闭所有工具提示
  document.addEventListener('click', function(e) {
    if (!e.target.closest('.tooltip')) {
      document.querySelectorAll('.tooltip__content').forEach(content => {
        content.style.opacity = '0';
        content.style.visibility = 'hidden';
      });
    }
  });
});
</script>

CSS

css
/* Tooltip.css */
.tooltip {
  position: relative;
  display: inline-block;
}

.tooltip__content {
  position: absolute;
  z-index: var(--z-tooltip, 1000);
  padding: var(--space-2) var(--space-3);
  background-color: var(--color-text);
  color: var(--color-text-inverse);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: var(--leading-normal);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--duration-fast) var(--ease-default),
              visibility var(--duration-fast) var(--ease-default),
              transform var(--duration-fast) var(--ease-default);
  pointer-events: none;
}

/* 箭头 */
.tooltip__content::after {
  content: '';
  position: absolute;
  border-style: solid;
  border-width: 6px;
}

/* 顶部方向 */
.tooltip--top .tooltip__content {
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%) translateY(8px);
  margin-bottom: 8px;
}

.tooltip--top .tooltip__content::after {
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-color: var(--color-text) transparent transparent transparent;
}

.tooltip--top:hover .tooltip__content,
.tooltip--top:focus-within .tooltip__content {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* 底部方向 */
.tooltip--bottom .tooltip__content {
  top: 100%;
  left: 50%;
  transform: translateX(-50%) translateY(-8px);
  margin-top: 8px;
}

.tooltip--bottom .tooltip__content::after {
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-color: transparent transparent var(--color-text) transparent;
}

.tooltip--bottom:hover .tooltip__content,
.tooltip--bottom:focus-within .tooltip__content {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}

/* 左侧方向 */
.tooltip--left .tooltip__content {
  right: 100%;
  top: 50%;
  transform: translateY(-50%) translateX(8px);
  margin-right: 8px;
}

.tooltip--left .tooltip__content::after {
  left: 100%;
  top: 50%;
  transform: translateY(-50%);
  border-color: transparent transparent transparent var(--color-text);
}

.tooltip--left:hover .tooltip__content,
.tooltip--left:focus-within .tooltip__content {
  opacity: 1;
  visibility: visible;
  transform: translateY(-50%) translateX(0);
}

/* 右侧方向 */
.tooltip--right .tooltip__content {
  left: 100%;
  top: 50%;
  transform: translateY(-50%) translateX(-8px);
  margin-left: 8px;
}

.tooltip--right .tooltip__content::after {
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  border-color: transparent var(--color-text) transparent transparent;
}

.tooltip--right:hover .tooltip__content,
.tooltip--right:focus-within .tooltip__content {
  opacity: 1;
  visibility: visible;
  transform: translateY(-50%) translateX(0);
}

/* 触发元素 */
.tooltip__trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* 不同颜色变体 */
.tooltip--success .tooltip__content {
  background-color: var(--color-success);
}

.tooltip--success .tooltip__content::after {
  border-color: var(--color-success) transparent transparent transparent;
}

.tooltip--warning .tooltip__content {
  background-color: var(--color-warning);
}

.tooltip--warning .tooltip__content::after {
  border-color: var(--color-warning) transparent transparent transparent;
}

.tooltip--danger .tooltip__content {
  background-color: var(--color-danger);
}

.tooltip--danger .tooltip__content::after {
  border-color: var(--color-danger) transparent transparent transparent;
}

/* 禁用状态 */
.tooltip--disabled {
  pointer-events: none;
}

.tooltip--disabled .tooltip__content {
  display: none;
}

/* 响应式 */
@media (max-width: 640px) {
  .tooltip__content {
    font-size: 10px;
    padding: var(--space-1) var(--space-2);
  }
}

AI 使用说明

组件名: tooltip
选择器: .tooltip
依赖: /tokens/tokens.css
文件: /components/tooltip/tooltip.html

纯 HTML + CSS,零框架依赖,AI 友好