// z-indexをmap化して管理する
$z-index: (global-header, drawer-menu);
@function z-index($module) {
@return index($z-index, $module);
}
html {
box-sizing: border-box;
font-size: 75%;
-webkit-font-smoothing: subpixel-antialiased;
-moz-osx-font-smoothing: auto;
@media screen and (min-width: 768px) {
font-size: 87.5%;
}
@media screen and (min-width: 1200px) {
font-size: 100%;
}
}
:root {
--base-color: #434a56;
--white-color-primary: #f7f8f8;
--gray-color-primary: #676f79;
--gray-color-secondary: #e2e2e2;
--gray-color-tertiary: #aaa;
--active-color: #006e9b;
--header-height: 52px;
@media screen and (min-width: 768px) {
--header-height: 56px;
}
@media screen and (min-width: 1200px) {
--header-height: 60px;
}
}
*,
*::before,
*::after {
box-sizing: inherit;
margin: 0;
}
body {
background-color: var(--white-color-primary);
color: var(--base-color);
font-family: "Helvetica Neue", "Segoe UI", "Hiragino Sans",
"Hiragino Kaku Gothic ProN", Meiryo, sans-serif;
font-size: 1em;
line-height: 1.5;
}
.menu-button {
appearance: none;
background-color: var(--base-color);
border: none;
box-shadow: 0 0 12px rgba(0, 0, 0, 0.15);
cursor: pointer;
height: var(--header-height);
padding: 0;
position: relative;
transition: background-color 0.3s;
width: var(--header-height);
&.focus-visible {
background-color: var(--gray-color-primary);
}
@media (hover) {
&:hover {
background-color: var(--gray-color-primary);
}
}
}
.menu-button__icon {
bottom: 0;
height: 2px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 18px;
&::before,
&::after {
background-color: var(--white-color-primary);
content: "";
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
}
&[data-type="open"] {
background-color: var(--white-color-primary);
&::before {
transform: translateY(-6px);
}
&::after {
transform: translateY(6px);
}
}
&[data-type="close"] {
&::before {
transform: rotate(45deg);
}
&::after {
transform: rotate(-45deg);
}
}
}
.drawer-menu {
height: 100dvh;
left: 0;
overflow: hidden;
position: fixed;
top: 0;
width: 100%;
z-index: z-index(drawer-menu);
}
.drawer-menu__overlay {
animation-duration: var(--menu-toggle-duration);
animation-fill-mode: forwards;
background-color: rgba(0, 0, 0, 0.1);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: -1;
.drawer-menu:not([inert]) & {
animation-name: menu-overlay-appeared;
}
.drawer-menu[inert] & {
animation-name: menu-overlay-leaved;
}
}
@keyframes menu-overlay-appeared {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes menu-overlay-leaved {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.drawer-menu__container {
animation-duration: var(--menu-toggle-duration);
animation-fill-mode: forwards;
background-color: var(--white-color-primary);
border-left: var(--gray-color-secondary) 1px solid;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
height: 100%;
max-width: 440px;
min-width: 280px;
overflow: hidden;
position: absolute;
right: 0;
top: 0;
width: 80%;
.drawer-menu[inert] & {
animation-name: menu-container-leaved;
}
.drawer-menu:not([inert]) & {
animation-name: menu-container-appeared;
}
}
@keyframes menu-container-appeared {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(0);
}
}
@keyframes menu-container-leaved {
0% {
transform: translateX(0);
}
100% {
transform: translateX(100%);
}
}
.drawer-menu__list {
flex: 1;
list-style: none;
margin: 0;
overflow-y: auto;
padding: 0;
}
.drawer-menu__item {
border-bottom: var(--gray-color-secondary) 1px dashed;
}
.drawer-menu__link {
align-items: center;
color: inherit;
display: block;
justify-content: space-between;
letter-spacing: 0.01em;
padding: 1em 2.5em 1em 2em;
position: relative;
text-decoration: none;
transition: background-color 0.3s;
&::after {
border-right: 2px solid var(--gray-color-tertiary);
border-top: 2px solid var(--gray-color-tertiary);
bottom: 0;
content: "";
display: inline-block;
height: max(8px, 0.5em);
margin: auto 0;
position: absolute;
right: 24px;
top: 0;
transform: rotate(45deg);
width: max(8px, 0.5em);
}
&:focus {
background-color: rgba(0, 0, 0, 0.05);
}
&[aria-current] {
background-color: rgba(0, 0, 0, 0.1);
&::after {
content: none;
}
}
@media (hover) {
&:hover {
background-color: rgba(0, 0, 0, 0.05);
}
}
}
.drawer-menu__en-label {
display: block;
font-family: "Montserrat", sans-serif;
font-weight: 500;
text-transform: uppercase;
}
.drawer-menu__jp-label {
color: var(--gray-color-tertiary);
display: block;
font-size: max(10px, 0.75em);
}
.drawer-menu__close-button {
border-bottom: var(--gray-color-secondary) 1px solid;
order: -1;
text-align: right;
}
.global-header {
background-color: var(--white-color-primary);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
height: var(--header-height);
position: sticky;
top: 0;
z-index: z-index(global-header);
}
.global-header__container {
align-items: center;
display: flex;
justify-content: space-between;
&::before {
content: "";
display: inline-block;
width: var(--header-height);
}
}
.logo {
font-family: "Lobster", cursive;
font-size: 20px; // 拡大しないようにあえてのpx指定
margin: 0;
white-space: nowrap;
}
.main-content {
overflow-x: hidden;
padding: 4.5em 5%;
}
.article {
font-size: 1rem;
margin: auto;
max-width: 1024px;
}
.article__title {
font-size: 1.778em;
font-weight: normal;
margin: 0;
}
.article__sentence {
line-height: 1.75;
margin-top: 1.5em;
& > p + p {
margin-top: 1em;
}
}
.article__section {
margin-top: 2em;
}
.article__subtitle {
border-bottom: 2px solid var(--gray-color-secondary);
font-size: 1.333em;
font-weight: normal;
padding: 0.2em 0;
}
.article__list {
display: table;
margin-top: 1.5em;
padding: 0;
}
.article__list-item {
display: flex;
& + & {
margin-top: 0.5em;
}
&::before {
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
content: "";
display: inline-block;
flex-shrink: 0;
height: 1.5em;
margin-right: 0.5em;
vertical-align: middle;
width: 1.5em;
}
&.-checked {
&::before {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%20%3Cpath%20d%3D%22M9.86%2018a1%201%200%200%201-.73-.32l-4.86-5.17a1%201%200%201%201%201.46-1.37l4.12%204.39%208.41-9.2a1%201%200%201%201%201.48%201.34l-9.14%2010a1%201%200%200%201-.73.33z%22%20fill%3D%22%2344c08a%22%2F%3E%3C%2Fsvg%3E");
}
}
&.-not-checked {
&::before {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%20%3Cpath%20d%3D%22M13.41%2012l4.3-4.29a1%201%200%201%200-1.42-1.42L12%2010.59l-4.29-4.3a1%201%200%200%200-1.42%201.42l4.3%204.29-4.3%204.29a1%201%200%200%200%200%201.42%201%201%200%200%200%201.42%200l4.29-4.3%204.29%204.3a1%201%200%200%200%201.42%200%201%201%200%200%200%200-1.42z%22%20fill%3D%22%23f72f47%22%20%2F%3E%3C%2Fsvg%3E");
}
}
&.-link {
&::before {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224px%22%20height%3D%2224px%22%20viewBox%3D%220%200%2024%2024%22%20stroke%3D%22%23676f79%22%20stroke-width%3D%221%22%20stroke-linecap%3D%22square%22%20stroke-linejoin%3D%22miter%22%20fill%3D%22none%22%3E%20%3Crect%20width%3D%2213%22%20height%3D%2213%22%20x%3D%223%22%20y%3D%223%22%20%2F%3E%20%3Cpolyline%20points%3D%2216%208%2021%208%2021%2021%208%2021%208%2016%22%20%2F%3E%3C%2Fsvg%3E");
}
}
}
.article__link {
color: var(--active-color);
@media (hover) {
&:hover {
opacity: 0.8;
text-decoration: none;
}
}
}
.js-focus-visible :focus:not(.focus-visible) {
outline: 0;
}
[inert] {
cursor: default;
pointer-events: none;
}
[inert],
[inert] * {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.u-visually-hidden {
border: 0 !important;
clip: rect(0 0 0 0) !important;
clip-path: inset(50%) !important;
height: 1px !important;
margin: -1px !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
white-space: nowrap !important;
width: 1px !important;
}
View Compiled
const attachEvent = (element, event, handler, options) => {
element.addEventListener(event, handler, options);
return {
unsubscribe() {
element.removeEventListener(event, handler);
}
};
};
// export { attachEvent }
const backfaceFixed = (fixed) => {
/**
* 表示されているスクロールバーとの差分を計測し、背面固定時はその差分body要素に余白を生成する
*/
const scrollbarWidth = window.innerWidth - document.body.clientWidth;
document.body.style.paddingRight = fixed ? `${scrollbarWidth}px` : "";
/**
* 背面固定する対象を決定する
*/
const scrollingElement =
"scrollingElement" in document
? document.scrollingElement
: document.documentElement;
/**
* 背面固定時に変数にスクロール量を格納
*/
const scrollY = fixed
? scrollingElement.scrollTop
: parseInt(scrollingElement.style.top || "0");
/**
* CSSで背面を固定
*/
const styles = {
height: "100vh",
left: "0",
overflow: "hidden",
position: "fixed",
top: `${scrollY * -1}px`,
width: "100vw"
};
Object.keys(styles).forEach((key) => {
scrollingElement.style[key] = fixed ? styles[key] : "";
});
/**
* 背面固定解除時に元の位置にスクロールする
*/
if (!fixed) window.scrollTo(0, scrollY * -1);
};
// export { backfaceFixed }
// import { attachEvent } from '../utils/attachEvent'
// import { backfaceFixed } from '../utils/backfaceFixed'
class DrawerMenu {
constructor(root, options) {
this.root = root;
if (!this.root) return;
const defaultOptions = {
openTriggerSelector: ".js-menu-open-trigger", // メニューを開く際のターゲットとなるセレクタ
closeTriggerSelector: ".js-menu-close-trigger", // メニューを閉じる際のターゲットとなるセレクタ
inertTargetSelector: "#js-contents-wrapper", // 開いている時はこのセレクタを読み上げ対象外にする。
clickLinkToClose: true, // メニュー内のリンクをクリック時にメニューを閉じるか
toggleDuration: 500 // メニューの遷移時間
};
const mergedOptions = Object.assign(defaultOptions, options);
this.options = mergedOptions;
/**
* メニューを開くトリガーとなるセレクタの設定
*/
this.openTrigger = document.querySelector(this.options.openTriggerSelector);
if (!this.openTrigger)
throw TypeError("メニューを開く要素が見つかりません");
/**
* ボタンとは別にメニューを閉じるトリガーとなるセレクタの設定
* メニュー内のリンクをクリック時にメニューを閉じる設定をしている場合はメニュー内のa要素をクリック時にもメニューを閉じる
*/
this.closeTrigger = document.querySelectorAll(
this.options.closeTriggerSelector
);
/**
* メニュー内のリンクをクリック時にメニューを閉じる設定をしている場合はメニュー内のa要素をクリック時にもメニューを閉じる
*/
this.innerLink = this.root.querySelectorAll("a:not(.js-ignore-target)");
/**
* メニューが開かれている際に読み上げ対象外とするセレクタの指定
*/
this.inertTarget = document.querySelector(this.options.inertTargetSelector);
if (!this.inertTarget)
throw TypeError("inert対象のセレクタの指定は必須です");
/**
* イベントハンドラの設定
*/
this.openTriggerHandler = this.handleOpenTriggerClick.bind(this);
this.closeTriggerHandler = this.handleCloseTriggerClick.bind(this);
this.innerLinkHandler = this.handleInnerLinkClick.bind(this);
this.keyupHandler = this.handleKeyup.bind(this);
}
init() {
/**
* 状態を格納する変数
*/
this.isExpanded = false; // メニューの開閉状態を格納する
/**
* 初期化時に属性を付与
*/
this.prepareAttributes();
attachEvent(this.openTrigger, "click", this.openTriggerHandler);
}
prepareAttributes() {
this.root.setAttribute("role", "dialog");
this.root.setAttribute("aria-modal", "true");
this.root.setAttribute("tabindex", "-1");
this.root.setAttribute("inert", "");
this.root.style.display = "none";
this.openTrigger.setAttribute("aria-haspopup", "true");
document.documentElement.style.setProperty(
"--menu-toggle-duration",
`${this.options.toggleDuration}ms`
);
}
handleOpenTriggerClick(event) {
event.preventDefault();
this.open();
}
handleCloseTriggerClick(event) {
event.preventDefault();
this.close();
}
handleInnerLinkClick(event) {
this.close();
}
handleKeyup(event) {
if (event.key === "Escape" || event.key === "Esc") this.close();
}
open() {
// メニューの`display:none`を削除
this.root.style.display = "";
// Esc押下時イベントを追加
attachEvent(document, "keyup", this.keyupHandler);
// 開くボタンクリック時のイベントを削除
attachEvent(
this.openTrigger,
"click",
this.openTriggerHandler
).unsubscribe();
// 閉じるボタンクリック時のイベントを追加
this.closeTrigger.forEach((trigger) => {
attachEvent(trigger, "click", this.closeTriggerHandler);
});
// メニュー内リンククリック時のイベントを削除
if (this.options.clickLinkToClose) {
this.innerLink.forEach((link) => {
attachEvent(link, "click", this.innerLinkHandler);
});
}
backfaceFixed(true);
this.changeAttribute(true);
setTimeout(() => {
this.root.focus();
this.isExpanded = true;
}, 100);
}
close() {
// Esc押下時のイベントを削除
attachEvent(document, "keyup", this.keyupHandler).unsubscribe();
// 閉じるボタンクリック時のイベントを削除
this.closeTrigger.forEach((trigger) => {
attachEvent(trigger, "click", this.closeTriggerHandler).unsubscribe();
});
// メニュー内リンククリック時のイベントを削除
if (this.options.clickLinkToClose) {
this.innerLink.forEach((link) => {
attachEvent(link, "click", this.innerLinkHandler).unsubscribe();
});
}
backfaceFixed(false);
this.changeAttribute(false);
setTimeout(() => {
// 開くボタンクリック時のイベントを再登録
attachEvent(this.openTrigger, "click", this.openTriggerHandler);
// メニューに`hidden`を付与
this.root.style.display = "none";
// 開くボタンにフォーカスを移動
this.openTrigger.focus();
this.isExpanded = false;
}, this.options.toggleDuration);
}
changeAttribute(expanded) {
if (expanded) {
this.root.removeAttribute("inert");
this.openTrigger.setAttribute("inert", "");
this.inertTarget.setAttribute("inert", "");
} else {
this.root.setAttribute("inert", "");
this.openTrigger.removeAttribute("inert");
this.inertTarget.removeAttribute("inert");
}
}
}
document.addEventListener("DOMContentLoaded", () => {
const drawerElement = document.getElementById("js-menu-content");
const drawer = new DrawerMenu(drawerElement);
drawer.init();
});
View Compiled