Dropdown 下拉菜单
实时预览
引入
html
<link rel="stylesheet" href="/tokens/tokens.css">
<link rel="stylesheet" href="/components/dropdown/dropdown.css">代码
HTML
html
<!-- Dropdown Component — 2 variants: default, split -->
<!-- Demo: Dropdown 组件 -->
<div style="display: flex; flex-wrap: wrap; gap: 24px; align-items: flex-start; padding: 20px;">
<!-- Default Dropdown -->
<div class="dropdown">
<button class="dropdown__trigger">
操作菜单
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<div class="dropdown__menu">
<div class="dropdown__group">
<div class="dropdown__group-title">用户操作</div>
<a href="#" class="dropdown__item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
个人资料
</a>
<a href="#" class="dropdown__item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="3"></circle>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
</svg>
设置
</a>
</div>
<div class="dropdown__divider"></div>
<div class="dropdown__group">
<a href="#" class="dropdown__item dropdown__item--danger">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
<polyline points="16 17 21 12 16 7"></polyline>
<line x1="21" y1="12" x2="9" y2="12"></line>
</svg>
退出登录
</a>
</div>
</div>
</div>
<!-- Split Dropdown -->
<div class="dropdown dropdown--split">
<button class="dropdown__trigger">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 5v14M5 12h14"></path>
</svg>
新建项目
</button>
<button class="dropdown__trigger dropdown__split-trigger">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<div class="dropdown__menu">
<a href="#" class="dropdown__item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
<line x1="3" y1="9" x2="21" y2="9"></line>
<line x1="9" y1="21" x2="9" y2="9"></line>
</svg>
创建文件夹
</a>
<a href="#" class="dropdown__item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="12" y1="18" x2="12" y2="12"></line>
<line x1="9" y1="15" x2="15" y2="15"></line>
</svg>
创建文件
</a>
<a href="#" class="dropdown__item">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="16 18 22 12 16 6"></polyline>
<polyline points="8 6 2 12 8 18"></polyline>
</svg>
从模板创建
</a>
</div>
</div>
<!-- Right-aligned Dropdown -->
<div class="dropdown">
<button class="dropdown__trigger">
右对齐菜单
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<div class="dropdown__menu dropdown__menu--right">
<a href="#" class="dropdown__item">选项一</a>
<a href="#" class="dropdown__item">选项二</a>
<a href="#" class="dropdown__item">选项三</a>
</div>
</div>
</div>CSS
css
/* Dropdown.css */
.dropdown {
position: relative;
display: inline-block;
font-family: var(--font-sans);
}
/* ── 触发按钮 ──────────────────────────── */
.dropdown__trigger {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-2);
padding: 10px 22px;
font-size: var(--text-base);
font-weight: var(--weight-medium);
color: var(--color-text);
background: var(--color-surface);
border: 1.5px solid var(--color-border);
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--duration-normal) var(--ease-default);
user-select: none;
white-space: nowrap;
}
.dropdown__trigger:hover {
border-color: var(--color-border-hover);
background: var(--color-bg-subtle);
}
.dropdown__trigger:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
}
.dropdown__trigger svg {
width: 16px;
height: 16px;
transition: transform var(--duration-normal) var(--ease-default);
}
/* ── 菜单 ──────────────────────────── */
.dropdown__menu {
position: absolute;
top: calc(100% + var(--space-2));
left: 0;
min-width: 200px;
max-width: 320px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
padding: var(--space-2);
z-index: var(--z-dropdown);
opacity: 0;
visibility: hidden;
transform: translateY(-8px);
transition: all var(--duration-normal) var(--ease-default);
transform-origin: top left;
}
.dropdown__menu--right {
left: auto;
right: 0;
transform-origin: top right;
}
/* ── 显示菜单 ──────────────────────────── */
.dropdown:focus-within .dropdown__menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.dropdown:focus-within .dropdown__trigger svg {
transform: rotate(180deg);
}
/* ── 菜单项 ──────────────────────────── */
.dropdown__item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-4);
color: var(--color-text);
text-decoration: none;
border-radius: var(--radius-sm);
transition: all var(--duration-fast) var(--ease-default);
cursor: pointer;
font-size: var(--text-base);
line-height: 1;
}
.dropdown__item:hover {
background: var(--color-bg-muted);
color: var(--color-text);
}
.dropdown__item:active {
background: var(--color-primary-ghost);
}
.dropdown__item--danger {
color: var(--color-danger);
}
.dropdown__item--danger:hover {
background: rgba(239, 68, 68, 0.08);
color: var(--color-danger);
}
.dropdown__item svg {
width: 16px;
height: 16px;
flex-shrink: 0;
color: var(--color-text-muted);
}
.dropdown__item--danger svg {
color: var(--color-danger);
}
/* ── 分隔线 ──────────────────────────── */
.dropdown__divider {
height: 1px;
background: var(--color-border);
margin: var(--space-2) 0;
}
/* ── 分组 ──────────────────────────── */
.dropdown__group {
margin-bottom: var(--space-2);
}
.dropdown__group:last-child {
margin-bottom: 0;
}
.dropdown__group-title {
padding: var(--space-2) var(--space-4);
font-size: var(--text-xs);
font-weight: var(--weight-semibold);
color: var(--color-text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* ── Split 变体 ──────────────────────────── */
.dropdown--split {
display: inline-flex;
}
.dropdown--split .dropdown__trigger {
border-radius: var(--radius-md) 0 0 var(--radius-md);
border-right: none;
}
.dropdown--split .dropdown__trigger:last-child,
.dropdown--split .dropdown__split-trigger {
border-radius: 0 var(--radius-md) var(--radius-md) 0;
border-right: 1.5px solid var(--color-border);
padding: 10px 14px;
}
.dropdown--split .dropdown__split-trigger {
border-left: none;
}
.dropdown--split .dropdown__menu {
left: auto;
right: 0;
transform-origin: top right;
}
/* ── 暗黑模式适配 ──────────────────────────── */
[data-theme="dark"] .dropdown__trigger {
background: var(--color-surface);
color: var(--color-text);
border-color: var(--color-border);
}
[data-theme="dark"] .dropdown__trigger:hover {
background: var(--color-bg-subtle);
border-color: var(--color-border-hover);
}
[data-theme="dark"] .dropdown__menu {
background: var(--color-surface);
border-color: var(--color-border);
box-shadow: var(--shadow-xl);
}
[data-theme="dark"] .dropdown__item {
color: var(--color-text);
}
[data-theme="dark"] .dropdown__item:hover {
background: var(--color-bg-muted);
color: var(--color-text);
}
[data-theme="dark"] .dropdown__item--danger {
color: var(--color-danger);
}
[data-theme="dark"] .dropdown__item--danger:hover {
background: rgba(239, 68, 68, 0.15);
}
[data-theme="dark"] .dropdown__divider {
background: var(--color-border);
}
[data-theme="dark"] .dropdown__group-title {
color: var(--color-text-muted);
}AI 使用说明
组件名: dropdown
选择器: .dropdown
依赖: /tokens/tokens.css
文件: /components/dropdown/dropdown.html