汉堡菜单变关闭

三条菜单线折成一个 X:上下两条先在中间汇合再旋转,中间那条悄悄消失。

  • CSS
  • 按钮
  • 切换
  • 收录于

AI 提示词

用纯 CSS 配合 React 状态切换,制作从汉堡菜单变成关闭图标的按钮。在 44px 的按钮内画三条 22px × 2px 的圆头横条。用 aria-expanded 驱动状态。展开时分两步完成,总时长 360ms:先把上下两条移到中间(translateY ±7px),再分别旋转到 45deg 和 -45deg。做法是把 translate 和 rotate 作为两个独立属性过渡,并设置不同的延迟,这样打开时先移动后旋转,关闭时顺序反过来。中间那条在第一步中淡出并缩放到 0。aria-label 在“打开菜单”和“关闭菜单”之间切换。在 prefers-reduced-motion 下直接切换形状,不做过渡。

源代码

Demo.tsx
'use client'

import { useState } from 'react'
import s from './demo.module.css'

export default function HamburgerMorph({ labels }: { labels: Record<string, string> }) {
  const [open, setOpen] = useState(false)

  return (
    <button
      type="button"
      className={s.button}
      aria-expanded={open}
      aria-label={open ? labels.close : labels.open}
      onClick={() => setOpen(!open)}
    >
      <span className={s.bar} />
      <span className={s.bar} />
      <span className={s.bar} />
    </button>
  )
}
demo.module.css
.button {
  position: relative;
  width: 56px;
  height: 56px;
  border: 1px solid var(--stage-rule);
  border-radius: 14px;
  background: var(--stage-surface);
  cursor: pointer;
}

.button:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; }

.bar {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 22px;
  height: 2px;
  margin: -1px 0 0 -11px;
  border-radius: 2px;
  background: var(--stage-ink);
  /* closing: rotate back first, then spread out */
  transition: translate 180ms var(--ease-out) 180ms, rotate 180ms var(--ease-out), opacity 180ms 180ms, scale 180ms 180ms;
}

.bar:nth-child(1) { translate: 0 -7px; }
.bar:nth-child(3) { translate: 0 7px; }

.button[aria-expanded='true'] .bar {
  /* opening: meet in the middle first, then rotate */
  transition: translate 180ms var(--ease-out), rotate 180ms var(--ease-out) 180ms, opacity 180ms, scale 180ms;
  background: var(--stage-accent);
}

.button[aria-expanded='true'] .bar:nth-child(1) { translate: 0 0; rotate: 45deg; }
.button[aria-expanded='true'] .bar:nth-child(2) { opacity: 0; scale: 0 1; }
.button[aria-expanded='true'] .bar:nth-child(3) { translate: 0 0; rotate: -45deg; }

@media (prefers-reduced-motion: reduce) {
  .bar, .button[aria-expanded='true'] .bar { transition: none; }
}

投稿创意

看到想收录的动效或主题?简单描述一下,会打开一个预先填好的 GitHub Issue,确认后即可提交。

你想投稿的是?

需要 GitHub 账号,投稿内容会公开。