← 全部文章

悬浮胶囊导航的实现笔记

日期 —
September 10, 2026
标签 —
CSS, 前端

这个站的导航栏有两种状态:顶部时是通栏白条,滚动后收缩成居中的悬浮胶囊。记录一下实现思路。

核心思路

只让一个元素负责所有变化,用 data-scrolled 属性驱动两套样式,中间靠 CSS transition 补间:

.nav-shell {
  height: 4rem;
  max-width: 100%;
  border-radius: 0;
  border-bottom: 1px solid var(--line);
  transition: height .35s cubic-bezier(.22,1,.36,1), max-width .35s cubic-bezier(.22,1,.36,1);
}

.nav-shell[data-scrolled='true'] {
  height: 3.75rem;
  max-width: min(62.5rem, calc(100% - 2.5rem));
  margin-top: 1.25rem;
  border-radius: 999px;
  box-shadow: 0 12px 32px -8px rgb(0 0 0 / .12);
}

JS 只有三行:监听 scroll,超过 16px 就把属性设为 true。

几个坑

  • height 从 4rem 变 3.75rem 看似多余,但胶囊比通栏“矮一点”才有收缩感
  • 投影要单独过渡,不能混在 all 里,否则首帧会闪
  • 外层容器 pointer-events-none、内层 pointer-events-auto,这样顶部与胶囊之间的空隙不会挡住点击
  • 记得处理 prefers-reduced-motion,动画虽小,尊重是必须的