找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4003

积分

0

好友

527

主题
发表于 1 小时前 | 查看: 3| 回复: 0

你一定遇到过那种特别难用的移动端菜单。

点一下汉堡图标,等抽屉慢吞吞滑出来。然后,你在十几个链接里找自己真正需要的那个。点错,返回,再点。三十秒后,你已经关掉页面,去看竞争对手的网站了。

最可怕的是,你甚至说不清第一个网站到底哪里烦。它可能不是传统意义上的“设计很差”——图标也许没问题,颜色也许符合品牌,动效也许还挺顺。

真正出错的地方,藏得更深:有人为这个任务选错了菜单模式。

移动端导航,其实有 12 种常见模式。而它们最终都在回答同一组问题:用户多久需要它?它在产品结构里有多深?

就这两个问题。如果一个用户一场会话要点十次的入口,被你塞进汉堡抽屉里,那每次多出来的点击和动画,都会变成摩擦。如果你把 40 个设置分类塞进底部 Tab Bar,它就会变成没人想要的横向滚动灾难。

这两种失败,都不是审美问题,而是模式和任务不匹配。

下面这 12 种移动端菜单模式,每一种都有自己的频率和深度位置。看完之后,你选菜单时就不会再问“哪个看起来更高级”,而是会先问:这个入口,用户到底多常用?它到底应该露在多浅的位置?

1. 汉堡抽屉菜单

三个横线。点一下,一个面板从左侧滑出,通常覆盖屏幕宽度的 70% 到 80%,后面的内容会被半透明遮罩压暗。

<div class="p1-drawer" id="p1Drawer">
  <div class="p1-avatar"></div>
  <div class="p1-name">Naila Rehman</div>
  <div class="p1-email mono">@naila · Free plan</div>
  <ul class="p1-nav">
    <li><a href="#" class="active"><span class="dot"></span>Today</a></li>
    <li><a href="#"><span class="dot"></span>Archive</a></li>
    <li><a href="#"><span class="dot"></span>Favorites</a></li>
    <li><a href="#"><span class="dot"></span>Shared with me</a></li>
    <li><a href="#"><span class="dot"></span>Trash</a></li>
  </ul>
</div>
.p1-drawer {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 78%;
  background: var(--ink-soft);
  transform: translateX(-105%);
  transition: transform 0.38s cubic-bezier(0.65, 0, 0.35, 1);
  z-index: 30;
}

.p1-drawer.open {
  transform: translateX(0);
}

这里的 -105%-100% 更重要。它会把抽屉边缘彻底推出视口,避免因为舍入误差,在静止状态下露出一条细细的边。

汉堡抽屉菜单界面设计,左侧手机屏幕展示深色主题的汉堡菜单展开状态,包含用户信息和多个导航项,右侧配有说明文字Deep rarely-touched navigation及标签IOS ANDROID DEEP HIERARCHY LOW FREQUENCY

频率和深度:低频,深层。这个模式适合那些用户一场会话只碰一两次的东西,比如切换账号、退出登录、不常用设置、很少在任务中途打开的入口。

但只要抽屉里的某个项目开始被频繁点击,问题就来了——额外的一次点击,额外的一段动画。原本用户说不出口的“有点烦”,就是从这里开始积累的。

2. 侧边栏导航

一条常驻的竖向图标栏,通常宽 56 到 64px,固定在屏幕左侧。

<nav class="p2-rail" id="p2Rail">
  <button class="p2-item active" data-p2>
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <path d="M3 11l9-7 9 7v9a1 1 0 01-1 1h-5v-6H9v6H4a1 1 0 01-1-1z" />
    </svg>
    <span class="p2-label mono">Home</span>
  </button>
</nav>
.p2-rail {
  width: 64px;
  flex-shrink: 0;
  background: var(--ink-soft);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px 0;
  gap: 6px;
}

.p2-item.active {
  background: var(--accent);
  color: var(--ink);
}

侧边栏导航界面设计,左侧手机屏幕展示带图标的侧边栏布局,右侧文字说明Icons always in view及标签TABLETS FOLDABLES 3-5 DESTINATIONS ALWAYS VISIBLE

频率和深度:高频,浅层。它适合 3 到 5 个用户经常访问的目的地,并且这些入口需要一直露出来。它最大的好处是,不吃掉垂直空间。

但问题也很明显:它吃横向空间。在平板或折叠屏上,64px 是一个小成本。但在 375px 宽的手机竖屏上,它几乎吃掉了五分之一的可用宽度。所以这个模式真正适合的是平板、折叠屏、大屏设备,不是标准手机竖屏。

3. 底部 Tab Bar

3 到 5 个目的地,固定在屏幕底部。永远可见,拇指随时能点到,不需要额外打开菜单。

<nav class="p3-tabbar" id="p3Bar">
  <button class="p3-tab active" data-p3>
    <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <path d="M3 11l9-7 9 7v9a1 1 0 01-1 1h-5v-6H9v6H4a1 1 0 01-1-1z" />
    </svg>
    <span class="lab">HOME</span>
  </button>
  <button class="p3-tab" data-p3>...</button>
</nav>
.p3-tabbar {
  height: 64px;
  display: flex;
  border-top: 1px solid var(--line);
  background: var(--ink-soft);
}

.p3-tab.active::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 26px;
  height: 2.5px;
  background: var(--accent);
}

底部Tab Bar界面设计,左侧手机屏幕展示底部5个标签导航栏,右侧文字说明The default for a reason及标签3-5 ITEMS MAX ALWAYS VISIBLE THUMB ZONE

64px 不是随便定的。 Apple 对舒适点击区域的建议大约是 44pt。64px 可以同时容纳图标、文字标签和足够的上下留白,避免用户拇指误点。再小一点,误触率就会上升。尤其是在大屏手机上,底部栏距离单手握持的自然区域更远,容错空间更重要。

频率和深度:最高频,最浅层。这就是为什么底部 Tab Bar 会成为很多移动应用的默认选项。如果你不知道新 App 应该先从哪种导航开始,通常可以先从它开始。只有当你有明确理由时,再换成其他模式。

4. FAB 快捷操作菜单

一个圆形悬浮按钮,通常放在右下角。点击之后,展开 2 到 4 个小操作按钮。

<div class="p4-fab-wrap" id="p4Wrap">
  <button class="p4-fab" id="p4Main">
    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4">
      <path d="M12 5v14M5 12h14" />
    </svg>
  </button>
  <button class="p4-mini">...</button>
  <button class="p4-mini">...</button>
  <button class="p4-mini">...</button>
</div>
.p4-mini {
  opacity: 0;
  transform: translateY(10px) scale(0.7);
  transition: all 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
  pointer-events: none;
}

.p4-fab-wrap.open .p4-mini {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

.p4-fab-wrap.open .p4-mini:nth-child(2) { transition-delay: 0.03s; }
.p4-fab-wrap.open .p4-mini:nth-child(3) { transition-delay: 0.06s; }
.p4-fab-wrap.open .p4-mini:nth-child(4) { transition-delay: 0.09s; }

FAB快捷操作菜单界面设计,左侧手机屏幕展示底部浮动操作按钮,右侧文字说明One tap for the main verb及标签PRIMARY ACTION 2-4 RELATED ACTIONS FLOATS ABOVE CONTENT

每个小按钮比前一个晚 30ms 出现。这就是自然级联展开和同时弹出之间的差别。前者像动作,后者像开关。

频率和深度:一个超高频主操作,下面挂 2 到 4 个紧密相关的次操作。比如“创建”下面放创建文档、创建任务、创建笔记。如果这些子操作之间关系不够近,FAB speed dial 就会变得吵,它会从“快捷入口”变成一个小型杂货架。

5. 底部 Sheet

一个从屏幕底部升起的面板,覆盖一部分屏幕。可以点遮罩关闭,也可以向下拖拽关闭。

<div class="p5-sheet" id="p5Sheet">
  <div class="p5-handle"></div>
  <h4>Share to</h4>
  <div class="p5-row">
    <span class="ic">...</span>Send as message
  </div>
  <div class="p5-row">
    <span class="ic">...</span>Email a copy
  </div>
</div>
.p5-sheet {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  border-radius: 22px 22px 0 0;
  transform: translateY(100%);
  transition: transform 0.38s cubic-bezier(0.32, 0.72, 0, 1);
  z-index: 30;
}

.p5-sheet.open {
  transform: translateY(0);
}

.p5-handle {
  width: 36px;
  height: 4px;
  border-radius: 4px;
  background: var(--line);
  margin: 0 auto 18px;
}

底部Sheet菜单界面设计,左侧手机屏幕展示从底部弹出的分享菜单,右侧文字说明Dismissable not disruptive及标签SWIPE TO DISMISS SHARE FILTER SORT PRESERVES CONTEXT

顶部那条 handle 不是装饰。过去十年,主流移动系统已经教育用户:一条小横条,意味着“我可以拖”。你当然可以省掉它,用户最后也能猜出来,但会更慢,也会有更多人因为不确定而直接点遮罩退出。

频率和深度:中频,浅层,并且强依赖当前上下文。底部 Sheet 比整页跳转好的地方在于:用户还能看见一部分原来的界面,他没有完全丢失上下文。但这个优势只在内容很短、选择很明确时成立。如果 Sheet 里的内容长到需要多屏滚动,那它就不再是上下文选择,而是变成了一个被硬塞进组件里的页面。

6. Overflow 菜单

右上角三个竖点。点击之后,一个小下拉菜单从角落展开。

<button class="icon-btn" id="p6Toggle">
  <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
    <circle cx="12" cy="5" r="1.6" />
    <circle cx="12" cy="12" r="1.6" />
    <circle cx="12" cy="19" r="1.6" />
  </svg>
</button>
.p6-menu {
  position: absolute;
  top: 48px;
  right: 16px;
  width: 170px;
  transform-origin: top right;
  transform: scale(0.85);
  opacity: 0;
  pointer-events: none;
  transition: all 0.18s ease;
}

.p6-menu.open {
  transform: scale(1);
  opacity: 1;
  pointer-events: auto;
}

Overflow菜单界面设计,左侧手机屏幕展示右上角三点展开的下拉菜单,右侧文字说明For actions not navigation及标签SECONDARY ACTIONS TOP-RIGHT ANCHOR RARE TAPS

这里真正起作用的是:

transform-origin: top right;

菜单会从三个点所在的同一个角落向外展开。用户会觉得它是从触发点长出来的,而不是屏幕上某个地方突然冒出来。

频率和深度:低频,浅层。但它通常只服务于某一个具体对象,而不是整站导航,比如某条消息、某个文件、某张卡片的更多操作。如果里面有危险操作,比如删除,应该放最后,用分割线隔开,并使用不同颜色。这样用户快速扫一眼时,不用读完文字,也能知道“这个选项不一样”。

7. 网格菜单

类似启动器的图标网格。所有入口尺寸一样、权重一样、视觉处理一样,没有主次。

<div class="p7-grid">
  <button class="p7-cell">
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
      <rect x="3" y="3" width="7" height="7" />
      <rect x="14" y="3" width="7" height="7" />
      <rect x="3" y="14" width="7" height="7" />
      <rect x="14" y="14" width="7" height="7" />
    </svg>
    APPS
  </button>
</div>
.p7-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
  padding: 20px;
}

.p7-cell {
  aspect-ratio: 1;
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

网格菜单界面设计,左侧手机屏幕展示6个图标组成的网格布局,右侧文字说明No path implies importance及标签LAUNCHER-STYLE EQUAL WEIGHTING 6-9 ITEMS

频率和深度:这是 12 种模式里,唯一一个主动拒绝回答“频率”问题的模式。因为每个格子都一样大、一样重、一样被对待。这只有在 6 到 9 个目的地真的没有自然顺序时才合理。一旦其中某个入口被明显更频繁使用,扁平网格就开始隐藏真实存在的层级。这时候,侧边栏或 Tab Bar 会比网格更诚实。不要假装每个入口都一样重要——如果它们不一样,界面应该承认这一点。

8. 分段控制器

它严格来说不是导航。它切换的是当前屏幕上的内容视图,而不是把用户带到新的地方。

<div class="p8-seg" id="p8Seg">
  <div class="p8-thumb" id="p8Thumb"></div>
  <button class="active mono" data-p8>DAY</button>
  <button class="mono" data-p8>WEEK</button>
  <button class="mono" data-p8>MONTH</button>
</div>
.p8-thumb {
  position: absolute;
  top: 4px;
  bottom: 4px;
  left: 4px;
  width: calc(33.333% - 4px);
  background: var(--accent);
  border-radius: 9px;
  transition: transform 0.3s cubic-bezier(0.65, 0, 0.35, 1);
  z-index: 1;
}
document.querySelectorAll("#p8Seg [data-p8]").forEach((btn, i) => {
  btn.addEventListener("click", () => {
    document.querySelectorAll("#p8Seg [data-p8]").forEach((b) => b.classList.remove("active"));
    btn.classList.add("active");
    p8Thumb.style.transform = `translateX(${i * 100}%)`;
  });
});

分段控制器界面设计,左侧手机屏幕展示DAY WEEK MONTH三选项切换控件,右侧文字说明Not really a menu a toggle及标签2-4 OPTIONS SAME CONTENT NEW VIEW NO NAVIGATION

这里只需要一个 thumb 元素在当前激活标签下面滑动。通过 index 计算 translateX,就能替代三个单独的选中状态。

频率和深度:不适用。这正是重点。分段控制器经常被误当成导航——如果点击某一项后,用户应该进入一个新位置,并且返回按钮应该记录这次跳转,那它就不是分段控制器,而是穿着 toggle 外衣的导航。而这会让返回按钮、页面历史和用户预期一起出问题。

9. 手风琴列表

一组纵向堆叠的标题。点击标题,就在原地展开内容。通常打开一个时,会收起前一个。

<div class="p9-item open" data-p9>
  <button class="p9-head">
    <span>Workspace</span><span class="p9-chev">⌄</span>
  </button>
  <div class="p9-body">
    <div class="p9-body-inner">Members · Billing · Integrations</div>
  </div>
</div>
.p9-body {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.32s ease;
}

.p9-item.open .p9-body {
  max-height: 120px;
}

手风琴列表界面设计,左侧手机屏幕展示可展开的折叠列表组件,右侧文字说明Depth without leaving the page及标签SETTINGS SCREENS IN-PLACE EXPANSION SCANNABLE HEADERS

这个固定的 max-height 是一个捷径,不是理想解。CSS 不能直接从 height: 0 过渡到 height: auto,所以很多人会写一个硬编码的高度上限。如果内容短而且可预测,这样可以接受;但如果内容长度不可控,就应该用 JavaScript 读取 scrollHeight,再动画到实际高度。否则,内容可能被意外裁掉。

频率和深度:中频,浅层展开。它的价值是:为了少量额外信息,避免跳到一个新页面。但只要展开内容长到需要多屏滚动,手风琴就不再是在节省一次跳转——它是在把一个真正的页面藏进一个不适合承载页面的组件里。

10. 长按上下文菜单

没有可见触发器。用户长按某个对象,短暂延迟后,一个浮动菜单出现在手指附近。

<div class="p10-card mono" id="p10Card">Hold this card ↓</div>
<div class="p10-ctx" id="p10Ctx" style="top: 180px; left: 60px">
  <button>Copy</button>
  <button>Forward</button>
  <button>Save</button>
</div>
let pressTimer;

function showCtx() {
  p10Ctx.classList.add("show");
  p10Card.classList.remove("pressed");
}

function startPress() {
  p10Card.classList.add("pressed");
  pressTimer = setTimeout(showCtx, 480);
}

function cancelPress() {
  clearTimeout(pressTimer);
  p10Card.classList.remove("pressed");
}

长按上下文菜单界面设计,左侧手机屏幕展示长按卡片后弹出的操作菜单,右侧文字说明Zero visual cost until it isnt及标签NO VISIBLE TRIGGER ITEM-SPECIFIC ACTIONS POWER-USER PATTERN

480ms 接近大多数平台对长按形成的非正式约定。短一点,用户只是慢点点击,也可能误触菜单;长一点,交互会变得像没反应,而不是像一个明确动作。

频率和深度:天然低频。这不是缺点,这是它存在的原因。在密集列表里,如果每一行都放一个可见按钮,会消耗太多注意力。长按菜单把这些低频操作藏起来,界面会更干净。但代价也很明显:可发现性几乎为零。如果某个功能藏在长按里,使用数据很低,不一定说明功能没价值——也可能只是没人发现它。

11. 全屏覆盖菜单

点击菜单触发器后,整个屏幕被导航视图替换,通常有大字号和更宽松的间距。

<div class="p11-overlay" id="p11Overlay">
  <div class="p11-top">
    <button class="icon-btn" id="p11Close">...</button>
  </div>
  <ul class="p11-links">
    <li><a href="#" class="active"><span class="n">01</span>New arrivals</a></li>
    <li><a href="#"><span class="n">02</span>Womenswear</a></li>
    <li><a href="#"><span class="n">03</span>Menswear</a></li>
  </ul>
</div>
.p11-overlay {
  position: absolute;
  inset: 0;
  z-index: 30;
  transform: translateY(-100%);
  transition: transform 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}

.p11-overlay.open {
  transform: translateY(0);
}

全屏覆盖菜单界面设计,左侧手机屏幕展示占据整个屏幕的导航目录,右侧文字说明Full attention nothing else及标签EDITORIAL COMMERCE TOTAL FOCUS FEW LARGE TARGETS

注意,它是沿 Y 轴滑入,而汉堡抽屉是沿 X 轴滑入。这不是随便选的。侧边抽屉像是在内容旁边揭开一层东西;全屏帘幕从顶部落下,则意味着:现在进入完整聚焦状态,别的内容都先让开。

频率和深度:低频,但不是深层。这是它有趣的地方。它适合 5 到 8 个浅层目的地,不是隐藏很深的账号设置,只是这些入口需要更强的视觉仪式感。当品牌希望“导航本身也被认真设计过”时,全屏覆盖菜单很有效。但如果用户一场会话要在几个 section 之间来回切几十次,每次都全屏接管,就会非常烦。

12. 舵形浮动工具栏

一个小型浮动胶囊,通常包含 2 到 3 个项目。悬在屏幕底部中央,而不是固定占据某条边。

<div class="p12-rudder" id="p12Bar">
  <button class="p12-item active" data-p12>...</button>
  <button class="p12-item mid" data-p12>...</button>
  <button class="p12-item" data-p12>...</button>
</div>
.p12-rudder {
  position: absolute;
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 6px;
  border-radius: 30px;
  box-shadow: 0 16px 32px -12px rgba(0, 0, 0, 0.6);
  z-index: 20;
}

.p12-item.mid {
  background: var(--accent);
  color: var(--ink);
  width: 42px;
  height: 42px;
}

舵形浮动工具栏界面设计,左侧手机屏幕展示底部中央悬浮的胶囊形工具按钮,右侧文字说明Floats so content can flow behind及标签2-3 CORE ACTIONS MEDIA-HEAVY SCREENS FLOATS OVER CONTENT

这个名字很贴切——它就像内容上的一个小舵。 position: absolute 和阴影负责把它从内容里分离出来,而不是像底部 Tab Bar 那样固定占用一整行布局空间。这对全屏图片、视频、地图等沉浸式内容尤其重要,因为那里每一像素的垂直空间都很贵。

频率和深度:高频,浅层。它和底部 Tab Bar 的使用画像很接近,但它被选择的理由不同:底下的内容需要呼吸。不过,它不适合长文本阅读页面,因为浮动胶囊迟早会挡住用户要看的内容。而且和固定底栏不同,它不会为自己预留空间,也就无法避免这种碰撞。


这十二种模式到底该怎么选?其实,根本的判断标准只有两个:用户多久需要它?它在结构里有多深?

回看一遍,你会发现这些模式天然地对应着不同的使用场景。高频且浅层的入口应该交给底部 Tab Bar、舵形浮动工具栏,以及那些不是真导航的分段控制器。低频且深层的东西才适合塞进汉堡抽屉或部分全屏覆盖菜单。像 Overflow 菜单和长按上下文菜单,它们绑定的是单个对象,而不是整体导航;网格菜单则适用于目的地之间没有真实层级的情况;底部 Sheet 和手风琴列表在原地展开内容,不会把用户送去新页面;侧边栏导航需要常驻可见,但只在更宽视口上才值得付出宽度成本;而 FAB 快捷操作菜单,是一个主操作带着几个紧密相关的子操作。

这些判断,和截图里哪个更好看关系不大。汉堡菜单经常被骂,很多时候也确实该骂,但它的问题不是“汉堡菜单天生坏”——真正的问题是,有人把高频入口塞进了低频模式里。如果只是放那些一场会话点两次的东西,汉堡抽屉依然是完全正确的选择。不管多少文章说 Tab Bar 才是现代答案,它也不该替代所有东西。

说到底,如果连入口的使用频率和结构深度都没想清楚,再花哨的产品设计也只是在错误的框架上涂脂抹粉。别先问“这个菜单好不好看”,先问:用户多久会点?它该放多深?模式应该在这两个答案之后出现,而不是在它们之前。




上一篇:iOS 27 这5个功能用过就烦,真心劝你别碰
下一篇:7个GitHub硬核项目:把Claude接进你的开发工作流,效率翻倍
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-7-12 02:22 , Processed in 0.622419 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表