📋 下拉菜单

使用 translateY 和 scaleY 实现平滑的菜单展开动画,支持多种过渡效果和延迟动画

使用的知识点: translateY() ↕️ scaleY() ⏱️ transition-delay 📍 transform-origin

交互演示

点击按钮体验三种不同的下拉菜单动画效果:

💡 提示:点击按钮打开菜单,再次点击或点击外部区域关闭菜单

实现步骤

步骤 1:HTML 结构

创建下拉菜单的基本结构,包含按钮和菜单内容:

HTML
<!-- 下拉菜单容器 -->
<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>

步骤 2:方式一 - 使用 translateY

使用 translateY 实现从上方滑入的效果:

CSS
.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);
}

步骤 3:方式二 - 使用 scaleY

使用 scaleY 实现垂直缩放展开的效果:

CSS
.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);
}

步骤 4:添加菜单项交错延迟

为菜单项添加递增的 transition-delay,实现依次出现的效果:

CSS
/* 菜单项初始状态 */
.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;
}

步骤 5:JavaScript 交互

添加点击事件来切换菜单的打开/关闭状态:

JavaScript
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'));
});

步骤 6:处理 overflow 和 clipping

正确处理菜单的溢出和裁剪,确保动画流畅:

CSS
.dropdown-menu {
  /* overflow: hidden 防止内容溢出 */
  overflow: hidden;

  /* 对于 scaleY,overflow: hidden 是必需的 */
  /* 它确保缩放时内容被正确裁剪 */
}

/* 如果需要滚动条(菜单项很多时)*/
.dropdown-menu {
  max-height: 300px;
  overflow-y: auto;
}

/* 但要注意:overflow-y: auto 与 scaleY 配合时 */
/* 可能需要在外层包裹一个容器 */

关键要点

← 返回实战应用列表