添加汉堡菜单

This commit is contained in:
2026-05-03 07:15:12 +08:00
Unverified
parent 09f36712e3
commit 18ef21d984
2 changed files with 130 additions and 3 deletions
+43 -1
View File
@@ -19,7 +19,18 @@ const { title = site.title } = Astro.props;
<body>
<header class="site-header" aria-label="网站导航">
<a class="brand" href="/">{site.className}</a>
<nav class="nav">
<button
class="nav-toggle"
type="button"
aria-label="打开菜单"
aria-controls="site-nav"
aria-expanded="false"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</button>
<nav class="nav" id="site-nav">
{navItems.map((item) => <a href={item.href}>{item.label}</a>)}
</nav>
</header>
@@ -27,5 +38,36 @@ const { title = site.title } = Astro.props;
<slot />
<footer>{site.footer}</footer>
<script>
const header = document.querySelector(".site-header");
const toggle = document.querySelector(".nav-toggle");
const nav = document.querySelector("#site-nav");
if (header && toggle && nav) {
const closeMenu = () => {
header.classList.remove("is-open");
toggle.setAttribute("aria-expanded", "false");
toggle.setAttribute("aria-label", "打开菜单");
};
toggle.addEventListener("click", () => {
const isOpen = header.classList.toggle("is-open");
toggle.setAttribute("aria-expanded", String(isOpen));
toggle.setAttribute("aria-label", isOpen ? "关闭菜单" : "打开菜单");
});
nav.addEventListener("click", (event) => {
if (event.target instanceof HTMLAnchorElement) {
closeMenu();
}
});
window.addEventListener("resize", () => {
if (window.matchMedia("(min-width: 821px)").matches) {
closeMenu();
}
});
}
</script>
</body>
</html>
+87 -2
View File
@@ -59,6 +59,32 @@ a {
white-space: nowrap;
}
.nav-toggle {
display: none;
width: 44px;
height: 44px;
place-items: center;
align-content: center;
justify-items: center;
gap: 5px;
border: 1px solid rgba(255, 253, 247, 0.36);
border-radius: 8px;
background: rgba(31, 43, 42, 0.2);
color: #fffdf7;
backdrop-filter: blur(12px);
cursor: pointer;
}
.nav-toggle span {
width: 20px;
height: 2px;
border-radius: 999px;
background: currentColor;
transition:
transform 180ms ease,
opacity 180ms ease;
}
.nav {
display: flex;
gap: clamp(12px, 2vw, 26px);
@@ -752,12 +778,71 @@ footer {
@media (max-width: 820px) {
.site-header {
align-items: flex-start;
position: absolute;
align-items: center;
flex-wrap: wrap;
gap: 12px;
padding-block: 12px;
}
.nav-toggle {
display: grid;
}
.nav {
display: none;
position: fixed;
top: 68px;
left: 16px;
right: 16px;
display: grid;
gap: 4px;
padding: 10px;
border: 1px solid rgba(255, 253, 247, 0.22);
border-radius: 8px;
background: rgba(31, 43, 42, 0.94);
box-shadow: 0 18px 44px rgba(13, 20, 19, 0.28);
opacity: 0;
pointer-events: none;
transform: translateY(-8px);
transition:
opacity 180ms ease,
transform 180ms ease;
backdrop-filter: blur(16px);
}
.nav a {
min-height: 44px;
display: flex;
align-items: center;
padding: 8px 12px;
border-radius: 7px;
opacity: 1;
}
.nav a:hover {
background: rgba(255, 253, 247, 0.12);
}
.site-header.is-open {
background: linear-gradient(180deg, rgba(22, 30, 29, 0.72), rgba(22, 30, 29, 0));
}
.site-header.is-open .nav {
opacity: 1;
pointer-events: auto;
transform: translateY(0);
}
.site-header.is-open .nav-toggle span:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}
.site-header.is-open .nav-toggle span:nth-child(2) {
opacity: 0;
}
.site-header.is-open .nav-toggle span:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}
.hero {