使用 translateY 和 scaleY 实现平滑的菜单展开动画,支持多种过渡效果和延迟动画
点击按钮体验三种不同的下拉菜单动画效果:
💡 提示:点击按钮打开菜单,再次点击或点击外部区域关闭菜单
创建下拉菜单的基本结构,包含按钮和菜单内容:
<!-- 下拉菜单容器 -->
<div class="dropdown">
<!-- 触发按钮 -->
<button class="dropdown-btn">
<span>选择操作</span>
<span class="dropdown-arrow">▼</span>
</button>
<!-- 下拉菜单内容 -->
<div class="dropdown-menu">
<a class="dropdown-item" href="#">编辑</a>
<a class="dropdown-item" href="#">复制</a>
<a class="dropdown-item" href="#">删除</a>
</div>
</div>
使用 translateY 实现从上方滑入的效果:
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-menu {
position: absolute;
top: calc(100% + 8px);
left: 0;
min-width: 100%;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
overflow: hidden;
z-index: 1000;
/* 初始状态:隐藏在上方 */
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 打开状态 */
.dropdown.open .dropdown-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
使用 scaleY 实现垂直缩放展开的效果:
.dropdown-menu {
position: absolute;
top: calc(100% + 8px);
left: 0;
min-width: 100%;
background: white;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
overflow: hidden;
z-index: 1000;
/* 初始状态:垂直缩放为 0 */
opacity: 0;
visibility: hidden;
transform: scaleY(0);
transform-origin: top;
/* transform-origin 设置为 top,从顶部开始展开 */
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.dropdown.open .dropdown-menu {
opacity: 1;
visibility: visible;
transform: scaleY(1);
}
为菜单项添加递增的 transition-delay,实现依次出现的效果:
/* 菜单项初始状态 */
.dropdown-menu .dropdown-item {
opacity: 0;
transform: translateX(-10px);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* 打开时显示菜单项 */
.dropdown.open .dropdown-menu .dropdown-item {
opacity: 1;
transform: translateX(0);
}
/* 为每个菜单项添加递增的延迟 */
.dropdown.open .dropdown-menu .dropdown-item:nth-child(1) {
transition-delay: 0.05s;
}
.dropdown.open .dropdown-menu .dropdown-item:nth-child(2) {
transition-delay: 0.1s;
}
.dropdown.open .dropdown-menu .dropdown-item:nth-child(3) {
transition-delay: 0.15s;
}
.dropdown.open .dropdown-menu .dropdown-item:nth-child(4) {
transition-delay: 0.2s;
}
.dropdown.open .dropdown-menu .dropdown-item:nth-child(5) {
transition-delay: 0.25s;
}
添加点击事件来切换菜单的打开/关闭状态:
const dropdowns = document.querySelectorAll('.dropdown');
dropdowns.forEach(dropdown => {
const btn = dropdown.querySelector('.dropdown-btn');
// 切换下拉菜单
btn.addEventListener('click', (e) => {
e.stopPropagation();
// 关闭其他下拉菜单
dropdowns.forEach(d => {
if (d !== dropdown) d.classList.remove('open');
});
// 切换当前菜单
dropdown.classList.toggle('open');
});
});
// 点击外部关闭所有菜单
document.addEventListener('click', () => {
dropdowns.forEach(d => d.classList.remove('open'));
});
正确处理菜单的溢出和裁剪,确保动画流畅:
.dropdown-menu {
/* overflow: hidden 防止内容溢出 */
overflow: hidden;
/* 对于 scaleY,overflow: hidden 是必需的 */
/* 它确保缩放时内容被正确裁剪 */
}
/* 如果需要滚动条(菜单项很多时)*/
.dropdown-menu {
max-height: 300px;
overflow-y: auto;
}
/* 但要注意:overflow-y: auto 与 scaleY 配合时 */
/* 可能需要在外层包裹一个容器 */