サイトヘッダー(レスポンシブナビ)
ロゴとグローバルナビのヘッダー。狭い画面ではハンバーガーメニューに切り替わり、aria-expanded とキーボード操作にも対応しています。
プレビュー
<header class="site-header">
<div class="site-header__inner">
<a class="site-header__logo" href="/">Highneeds</a>
<button
class="site-header__toggle"
type="button"
aria-expanded="false"
aria-controls="global-nav"
>
<span class="site-header__bars" aria-hidden="true"></span>
<span class="site-header__toggle-text">メニュー</span>
</button>
<nav class="site-header__nav" id="global-nav" aria-label="グローバルナビゲーション">
<ul class="site-header__list">
<li><a class="site-header__link" href="/thereed" aria-current="page">3Dサイト</a></li>
<li><a class="site-header__link" href="/snippets">スニペット</a></li>
<li><a class="site-header__link" href="/news">ニュース</a></li>
<li><a class="site-header__link" href="/columns">コラム</a></li>
<li><a class="site-header__cta" href="/contact">お問い合わせ</a></li>
</ul>
</nav>
</div>
</header>/* このスニペット配下だけ box-sizing を揃える(既存のリセットとは競合しません) */
.site-header,
.site-header *,
.site-header *::before,
.site-header *::after {
box-sizing: border-box;
}
.site-header {
--header-height: 60px;
--header-bg: #ffffff;
--header-border: #e5e7eb;
--header-fg: #111827;
--header-muted: #6b7280;
--header-accent: #2563eb;
--header-breakpoint: 768px;
position: sticky;
top: 0;
z-index: 50;
background: var(--header-bg);
border-bottom: 1px solid var(--header-border);
color: var(--header-fg);
font-size: 0.875rem;
}
.site-header__inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
max-width: 1152px;
height: var(--header-height);
margin: 0 auto;
padding: 0 1rem;
}
.site-header__logo {
flex: none;
color: inherit;
font-size: 1.125rem;
font-weight: 700;
text-decoration: none;
}
.site-header__list {
display: flex;
align-items: center;
gap: 1.5rem;
margin: 0;
padding: 0;
list-style: none;
}
.site-header__link {
color: var(--header-muted);
text-decoration: none;
transition: color 0.15s;
}
.site-header__link:hover,
.site-header__link[aria-current="page"] {
color: var(--header-fg);
}
.site-header__link[aria-current="page"] {
font-weight: 600;
}
.site-header__cta {
display: inline-block;
padding: 0.5rem 1rem;
border-radius: 6px;
background: var(--header-accent);
color: #ffffff;
text-decoration: none;
white-space: nowrap;
}
.site-header__cta:hover {
opacity: 0.9;
}
.site-header a:focus-visible,
.site-header button:focus-visible {
outline: 2px solid var(--header-accent);
outline-offset: 3px;
border-radius: 4px;
}
/* ハンバーガーボタン(広い画面では非表示) */
.site-header__toggle {
display: none;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
border: 0;
background: none;
color: inherit;
font: inherit;
cursor: pointer;
}
.site-header__toggle-text {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
/* 3本線。開いているときは×に変形する */
.site-header__bars,
.site-header__bars::before,
.site-header__bars::after {
display: block;
width: 20px;
height: 2px;
background: currentColor;
transition: transform 0.2s, opacity 0.2s;
}
.site-header__bars::before,
.site-header__bars::after {
content: "";
position: absolute;
}
.site-header__bars::before {
transform: translateY(-6px);
}
.site-header__bars::after {
transform: translateY(6px);
}
.site-header--open .site-header__bars {
background: transparent;
}
.site-header--open .site-header__bars::before {
transform: rotate(45deg);
}
.site-header--open .site-header__bars::after {
transform: rotate(-45deg);
}
@media (max-width: 767px) {
.site-header__toggle {
display: inline-flex;
position: relative;
}
.site-header__nav {
display: none;
position: absolute;
inset: var(--header-height) 0 auto;
background: var(--header-bg);
border-bottom: 1px solid var(--header-border);
box-shadow: 0 8px 24px rgb(0 0 0 / 8%);
}
.site-header--open .site-header__nav {
display: block;
}
.site-header__list {
flex-direction: column;
align-items: stretch;
gap: 0;
padding: 0.5rem 1rem 1rem;
}
.site-header__link {
display: block;
padding: 0.75rem 0;
border-bottom: 1px solid var(--header-border);
}
.site-header__cta {
margin-top: 0.75rem;
text-align: center;
}
}
@media (prefers-color-scheme: dark) {
.site-header {
--header-bg: #111827;
--header-border: #374151;
--header-fg: #f9fafb;
--header-muted: #9ca3af;
--header-accent: #3b82f6;
}
}
/* ここから下はプレビュー表示用です。コピーして使うときは不要です */
body {
margin: 0;
background: #ffffff;
font-family: system-ui, -apple-system, "Segoe UI", "Hiragino Sans",
"Noto Sans JP", sans-serif;
color: #111827;
}
@media (prefers-color-scheme: dark) {
body {
background: #111827;
color: #f9fafb;
}
}
const header = document.querySelector(".site-header");
const toggle = header.querySelector(".site-header__toggle");
const nav = header.querySelector(".site-header__nav");
function setOpen(open) {
toggle.setAttribute("aria-expanded", String(open));
header.classList.toggle("site-header--open", open);
}
toggle.addEventListener("click", function () {
setOpen(toggle.getAttribute("aria-expanded") !== "true");
});
// メニュー内のリンクを押したら閉じる
nav.addEventListener("click", function (event) {
if (event.target.closest("a")) setOpen(false);
});
// Escape で閉じてボタンにフォーカスを戻す
document.addEventListener("keydown", function (event) {
if (event.key === "Escape" && toggle.getAttribute("aria-expanded") === "true") {
setOpen(false);
toggle.focus();
}
});
// 広い画面に戻したときに開いた状態を持ち越さない
window.matchMedia("(min-width: 768px)").addEventListener("change", function (event) {
if (event.matches) setOpen(false);
});