Header basic
左にロゴ、右にメニュー。768px未満でハンバーガーメニュー。
2023年12月以降、すべてのブラウザーで利用可能です。
- Baseline
- BaselineWidely available
- 対応ブラウザ
- Chrome120+Edge120+Firefox117+Safari17.2+
- 使用機能
- CSS NestingMedia range syntax:where()Logical properties:focus-visibleprefers-reduced-motionany-hovergapgridflex
プレビューを読み込み中
<header class="header-basic js-header-basic">
<div class="header-basic__inner">
<a class="header-basic__logo" href="#" aria-label="トップページ">
<img
class="header-basic__logo-image"
src="/brand/logo.svg"
alt=""
width="89"
height="24"
decoding="async"
/>
</a>
<button
class="header-basic__toggle js-header-basic-toggle"
type="button"
aria-expanded="false"
aria-label="メニューを開く"
data-label-open="メニューを開く"
data-label-close="メニューを閉じる"
>
<span class="header-basic__toggle-line" aria-hidden="true"></span>
<span class="header-basic__toggle-line" aria-hidden="true"></span>
<span class="header-basic__toggle-line" aria-hidden="true"></span>
</button>
<nav
class="header-basic__nav js-header-basic-nav"
aria-label="メインメニュー"
>
<div class="header-basic__nav-inner">
<ul class="header-basic__list">
<li class="header-basic__item">
<a class="header-basic__link" href="#">Home</a>
</li>
<li class="header-basic__item">
<a class="header-basic__link" href="#">About</a>
</li>
<li class="header-basic__item">
<a class="header-basic__link" href="#">Contact</a>
</li>
</ul>
</div>
</nav>
</div>
</header>
<header class="header-basic js-header-basic">
<div class="header-basic__inner">
<a class="header-basic__logo" href="#" aria-label="トップページ">
<img
class="header-basic__logo-image"
src="/brand/logo.svg"
alt=""
width="89"
height="24"
decoding="async"
/>
</a>
<button
class="header-basic__toggle js-header-basic-toggle"
type="button"
aria-expanded="false"
aria-label="メニューを開く"
data-label-open="メニューを開く"
data-label-close="メニューを閉じる"
>
<span class="header-basic__toggle-line" aria-hidden="true"></span>
<span class="header-basic__toggle-line" aria-hidden="true"></span>
<span class="header-basic__toggle-line" aria-hidden="true"></span>
</button>
<nav
class="header-basic__nav js-header-basic-nav"
aria-label="メインメニュー"
>
<div class="header-basic__nav-inner">
<ul class="header-basic__list">
<li class="header-basic__item">
<a class="header-basic__link" href="#">Home</a>
</li>
<li class="header-basic__item">
<a class="header-basic__link" href="#">About</a>
</li>
<li class="header-basic__item">
<a class="header-basic__link" href="#">Contact</a>
</li>
</ul>
</div>
</nav>
</div>
</header>
/* reset */
:where(a).header-basic__logo {
text-decoration: none;
}
:where(img).header-basic__logo-image {
display: block;
}
:where(ul).header-basic__list {
padding: 0;
margin: 0;
list-style: none;
}
:where(button).header-basic__toggle {
box-sizing: border-box;
padding: 0;
font: inherit;
appearance: none;
cursor: pointer;
background: none;
border: none;
}
:where(a).header-basic__link {
text-decoration: none;
}
/* snippet */
.header-basic {
--header-background: #fff;
--header-border: #e7e7e7;
--header-link-color: #364153;
--header-link-color-hover: #2b36f5;
--header-toggle-color: #364153;
--header-interactive-background: #f5f5f5;
--header-focus-color: var(--header-link-color-hover);
width: 100%;
background-color: var(--header-background);
border-bottom: 1px solid var(--header-border);
}
.header-basic__inner {
display: grid;
grid-template-areas:
"logo toggle"
"nav nav";
column-gap: 16px;
align-items: center;
justify-content: space-between;
max-width: 1280px;
padding: 12px 24px;
margin-inline: auto;
@media (width >= 768px) {
grid-template-areas: "logo nav";
}
}
.header-basic__logo {
grid-area: logo;
}
.header-basic__logo-image {
width: 89px;
height: 24px;
}
.header-basic__toggle {
display: flex;
flex-direction: column;
grid-area: toggle;
gap: 5px;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
color: var(--header-toggle-color);
border-radius: 8px;
transition: background-color 0.3s;
@media (width >= 768px) {
display: none;
}
@media (any-hover: hover) {
&:hover {
background-color: var(--header-interactive-background);
}
}
}
.header-basic__toggle-line {
display: block;
width: 22px;
height: 2px;
background-color: currentcolor;
transition:
transform 0.2s ease,
opacity 0.2s ease;
}
.header-basic__nav {
display: grid;
grid-area: nav;
grid-template-rows: 0fr;
overflow: hidden;
@media (width >= 768px) {
grid-template-rows: 1fr;
justify-self: end;
overflow: visible;
}
}
.header-basic__nav-inner {
min-height: 0;
overflow: hidden;
@media (width >= 768px) {
overflow: visible;
}
}
.header-basic__list {
display: grid;
row-gap: 4px;
padding-block: 8px 4px;
@media (width >= 768px) {
display: flex;
column-gap: 8px;
padding-block: 0;
}
}
.header-basic__link {
display: block;
padding: 12px 8px;
font-size: 14px;
font-weight: 500;
color: var(--header-link-color);
border-radius: 8px;
transition:
color 0.3s,
background-color 0.3s;
@media (width >= 768px) {
padding: 8px 12px;
}
@media (any-hover: hover) {
&:hover {
color: var(--header-link-color-hover);
background-color: var(--header-interactive-background);
}
}
}
/* modifier: open */
.header-basic--open .header-basic__nav {
grid-template-rows: 1fr;
}
.header-basic--open:not(.header-basic--animating) .header-basic__nav,
.header-basic--open:not(.header-basic--animating) .header-basic__nav-inner {
overflow: visible;
}
.header-basic--open .header-basic__toggle-line:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.header-basic--open .header-basic__toggle-line:nth-child(2) {
opacity: 0;
}
.header-basic--open .header-basic__toggle-line:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
/* JS 未実行時(無効・読み込み失敗): 折りたたみは機能しないため常時表示 */
.header-basic:not(.header-basic--enhanced) .header-basic__nav {
grid-template-rows: 1fr;
}
.header-basic:not(.header-basic--enhanced) .header-basic__nav,
.header-basic:not(.header-basic--enhanced) .header-basic__nav-inner {
overflow: visible;
}
.header-basic:not(.header-basic--enhanced) .header-basic__toggle {
display: none;
}
.header-basic--enhanced.header-basic--animating .header-basic__nav {
transition: grid-template-rows 0.3s ease;
@media (width >= 768px) {
transition: none;
}
}
/* focus */
.header-basic__logo,
.header-basic__toggle,
.header-basic__link {
&:focus:not(:focus-visible) {
outline: none;
}
&:focus-visible {
outline: 2px solid var(--header-focus-color);
outline-offset: 0;
}
}
.header-basic__toggle:focus-visible {
background-color: var(--header-interactive-background);
}
.header-basic__link:focus-visible {
color: var(--header-link-color-hover);
background-color: var(--header-interactive-background);
}
/* reduced motion */
@media (prefers-reduced-motion: reduce) {
.header-basic__toggle,
.header-basic__toggle-line,
.header-basic__link,
.header-basic--enhanced.header-basic--animating .header-basic__nav {
transition: none;
}
}
/* reset */
:where(a).header-basic__logo {
text-decoration: none;
}
:where(img).header-basic__logo-image {
display: block;
}
:where(ul).header-basic__list {
padding: 0;
margin: 0;
list-style: none;
}
:where(button).header-basic__toggle {
box-sizing: border-box;
padding: 0;
font: inherit;
appearance: none;
cursor: pointer;
background: none;
border: none;
}
:where(a).header-basic__link {
text-decoration: none;
}
/* snippet */
.header-basic {
--header-background: #fff;
--header-border: #e7e7e7;
--header-link-color: #364153;
--header-link-color-hover: #2b36f5;
--header-toggle-color: #364153;
--header-interactive-background: #f5f5f5;
--header-focus-color: var(--header-link-color-hover);
width: 100%;
background-color: var(--header-background);
border-bottom: 1px solid var(--header-border);
}
.header-basic__inner {
display: grid;
grid-template-areas:
"logo toggle"
"nav nav";
column-gap: 16px;
align-items: center;
justify-content: space-between;
max-width: 1280px;
padding: 12px 24px;
margin-inline: auto;
@media (width >= 768px) {
grid-template-areas: "logo nav";
}
}
.header-basic__logo {
grid-area: logo;
}
.header-basic__logo-image {
width: 89px;
height: 24px;
}
.header-basic__toggle {
display: flex;
flex-direction: column;
grid-area: toggle;
gap: 5px;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
color: var(--header-toggle-color);
border-radius: 8px;
transition: background-color 0.3s;
@media (width >= 768px) {
display: none;
}
@media (any-hover: hover) {
&:hover {
background-color: var(--header-interactive-background);
}
}
}
.header-basic__toggle-line {
display: block;
width: 22px;
height: 2px;
background-color: currentcolor;
transition:
transform 0.2s ease,
opacity 0.2s ease;
}
.header-basic__nav {
display: grid;
grid-area: nav;
grid-template-rows: 0fr;
overflow: hidden;
@media (width >= 768px) {
grid-template-rows: 1fr;
justify-self: end;
overflow: visible;
}
}
.header-basic__nav-inner {
min-height: 0;
overflow: hidden;
@media (width >= 768px) {
overflow: visible;
}
}
.header-basic__list {
display: grid;
row-gap: 4px;
padding-block: 8px 4px;
@media (width >= 768px) {
display: flex;
column-gap: 8px;
padding-block: 0;
}
}
.header-basic__link {
display: block;
padding: 12px 8px;
font-size: 14px;
font-weight: 500;
color: var(--header-link-color);
border-radius: 8px;
transition:
color 0.3s,
background-color 0.3s;
@media (width >= 768px) {
padding: 8px 12px;
}
@media (any-hover: hover) {
&:hover {
color: var(--header-link-color-hover);
background-color: var(--header-interactive-background);
}
}
}
/* modifier: open */
.header-basic--open .header-basic__nav {
grid-template-rows: 1fr;
}
.header-basic--open:not(.header-basic--animating) .header-basic__nav,
.header-basic--open:not(.header-basic--animating) .header-basic__nav-inner {
overflow: visible;
}
.header-basic--open .header-basic__toggle-line:nth-child(1) {
transform: translateY(7px) rotate(45deg);
}
.header-basic--open .header-basic__toggle-line:nth-child(2) {
opacity: 0;
}
.header-basic--open .header-basic__toggle-line:nth-child(3) {
transform: translateY(-7px) rotate(-45deg);
}
/* JS 未実行時(無効・読み込み失敗): 折りたたみは機能しないため常時表示 */
.header-basic:not(.header-basic--enhanced) .header-basic__nav {
grid-template-rows: 1fr;
}
.header-basic:not(.header-basic--enhanced) .header-basic__nav,
.header-basic:not(.header-basic--enhanced) .header-basic__nav-inner {
overflow: visible;
}
.header-basic:not(.header-basic--enhanced) .header-basic__toggle {
display: none;
}
.header-basic--enhanced.header-basic--animating .header-basic__nav {
transition: grid-template-rows 0.3s ease;
@media (width >= 768px) {
transition: none;
}
}
/* focus */
.header-basic__logo,
.header-basic__toggle,
.header-basic__link {
&:focus:not(:focus-visible) {
outline: none;
}
&:focus-visible {
outline: 2px solid var(--header-focus-color);
outline-offset: 0;
}
}
.header-basic__toggle:focus-visible {
background-color: var(--header-interactive-background);
}
.header-basic__link:focus-visible {
color: var(--header-link-color-hover);
background-color: var(--header-interactive-background);
}
/* reduced motion */
@media (prefers-reduced-motion: reduce) {
.header-basic__toggle,
.header-basic__toggle-line,
.header-basic__link,
.header-basic--enhanced.header-basic--animating .header-basic__nav {
transition: none;
}
}
(function () {
let navIdCounter = 0;
const onLayoutChangeHandlers = [];
const isCollapsible = (toggle) =>
typeof toggle.checkVisibility === "function"
? toggle.checkVisibility()
: getComputedStyle(toggle).display !== "none";
const ensureNavId = (nav) => {
if (
nav.id &&
document.querySelectorAll(`#${CSS.escape(nav.id)}`).length === 1
) {
return nav.id;
}
let id;
do {
id = `header-basic-nav-${++navIdCounter}`;
} while (document.getElementById(id));
nav.id = id;
return nav.id;
};
document.querySelectorAll(".js-header-basic").forEach((header) => {
const toggle = header.querySelector(".js-header-basic-toggle");
const nav = header.querySelector(".js-header-basic-nav");
if (!toggle || !nav) return;
const labelOpen = toggle.dataset.labelOpen || "メニューを開く";
const labelClose = toggle.dataset.labelClose || "メニューを閉じる";
header.classList.add("header-basic--enhanced");
toggle.setAttribute("aria-controls", ensureNavId(nav));
const syncInert = () => {
const open = header.classList.contains("header-basic--open");
const animating = header.classList.contains("header-basic--animating");
if (!isCollapsible(toggle) || (open && !animating)) {
nav.removeAttribute("inert");
} else {
nav.setAttribute("inert", "");
}
};
const onEscapeKeydown = (event) => {
if (event.key !== "Escape") return;
if (!header.contains(document.activeElement)) return;
setOpen(false);
toggle.focus();
};
const setOpen = (open) => {
header.classList.toggle("header-basic--open", open);
toggle.setAttribute("aria-expanded", String(open));
toggle.setAttribute("aria-label", open ? labelClose : labelOpen);
syncInert();
if (open) {
document.addEventListener("keydown", onEscapeKeydown);
} else {
document.removeEventListener("keydown", onEscapeKeydown);
}
};
toggle.addEventListener("click", () => {
header.classList.add("header-basic--animating");
setOpen(!header.classList.contains("header-basic--open"));
if (parseFloat(getComputedStyle(nav).transitionDuration) === 0) {
header.classList.remove("header-basic--animating");
syncInert();
}
});
nav.addEventListener("transitionend", (event) => {
if (event.target !== nav) return;
if (event.propertyName !== "grid-template-rows") return;
header.classList.remove("header-basic--animating");
syncInert();
});
nav.addEventListener("click", (event) => {
const target = event.target;
if (!(target instanceof Element)) return;
if (target.closest("a[href]")) {
setOpen(false);
}
});
let wasCollapsible = isCollapsible(toggle);
const onLayoutChange = () => {
const collapsible = isCollapsible(toggle);
if (collapsible === wasCollapsible) return;
wasCollapsible = collapsible;
if (!collapsible) {
header.classList.remove("header-basic--animating");
setOpen(false);
} else {
syncInert();
}
};
onLayoutChangeHandlers.push(onLayoutChange);
syncInert();
});
let resizeRafId = 0;
window.addEventListener(
"resize",
() => {
if (resizeRafId) return;
resizeRafId = requestAnimationFrame(() => {
resizeRafId = 0;
onLayoutChangeHandlers.forEach((handler) => handler());
});
},
{ passive: true },
);
})();
(function () {
let navIdCounter = 0;
const onLayoutChangeHandlers = [];
const isCollapsible = (toggle) =>
typeof toggle.checkVisibility === "function"
? toggle.checkVisibility()
: getComputedStyle(toggle).display !== "none";
const ensureNavId = (nav) => {
if (
nav.id &&
document.querySelectorAll(`#${CSS.escape(nav.id)}`).length === 1
) {
return nav.id;
}
let id;
do {
id = `header-basic-nav-${++navIdCounter}`;
} while (document.getElementById(id));
nav.id = id;
return nav.id;
};
document.querySelectorAll(".js-header-basic").forEach((header) => {
const toggle = header.querySelector(".js-header-basic-toggle");
const nav = header.querySelector(".js-header-basic-nav");
if (!toggle || !nav) return;
const labelOpen = toggle.dataset.labelOpen || "メニューを開く";
const labelClose = toggle.dataset.labelClose || "メニューを閉じる";
header.classList.add("header-basic--enhanced");
toggle.setAttribute("aria-controls", ensureNavId(nav));
const syncInert = () => {
const open = header.classList.contains("header-basic--open");
const animating = header.classList.contains("header-basic--animating");
if (!isCollapsible(toggle) || (open && !animating)) {
nav.removeAttribute("inert");
} else {
nav.setAttribute("inert", "");
}
};
const onEscapeKeydown = (event) => {
if (event.key !== "Escape") return;
if (!header.contains(document.activeElement)) return;
setOpen(false);
toggle.focus();
};
const setOpen = (open) => {
header.classList.toggle("header-basic--open", open);
toggle.setAttribute("aria-expanded", String(open));
toggle.setAttribute("aria-label", open ? labelClose : labelOpen);
syncInert();
if (open) {
document.addEventListener("keydown", onEscapeKeydown);
} else {
document.removeEventListener("keydown", onEscapeKeydown);
}
};
toggle.addEventListener("click", () => {
header.classList.add("header-basic--animating");
setOpen(!header.classList.contains("header-basic--open"));
if (parseFloat(getComputedStyle(nav).transitionDuration) === 0) {
header.classList.remove("header-basic--animating");
syncInert();
}
});
nav.addEventListener("transitionend", (event) => {
if (event.target !== nav) return;
if (event.propertyName !== "grid-template-rows") return;
header.classList.remove("header-basic--animating");
syncInert();
});
nav.addEventListener("click", (event) => {
const target = event.target;
if (!(target instanceof Element)) return;
if (target.closest("a[href]")) {
setOpen(false);
}
});
let wasCollapsible = isCollapsible(toggle);
const onLayoutChange = () => {
const collapsible = isCollapsible(toggle);
if (collapsible === wasCollapsible) return;
wasCollapsible = collapsible;
if (!collapsible) {
header.classList.remove("header-basic--animating");
setOpen(false);
} else {
syncInert();
}
};
onLayoutChangeHandlers.push(onLayoutChange);
syncInert();
});
let resizeRafId = 0;
window.addEventListener(
"resize",
() => {
if (resizeRafId) return;
resizeRafId = requestAnimationFrame(() => {
resizeRafId = 0;
onLayoutChangeHandlers.forEach((handler) => handler());
});
},
{ passive: true },
);
})();