Created
January 14, 2021 23:38
-
-
Save tak-dcxi/078c40e601acd4a40320d2648c8f7239 to your computer and use it in GitHub Desktop.
Drawer Menu Pattern 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="website"> | |
<header id="js-website-header" class="website__header"> | |
<div class="global-header"> | |
<div class="global-header__title"> | |
<p class="logo">My Drawer Menu</p> | |
</div> | |
<div class="global-header__button"> | |
<button id="js-menu-button" class="menu-button" type="button" aria-label="メニュー"> | |
<span class="menu-button__icon"></span> | |
</button> | |
</div> | |
</div> | |
<!-- /.navbar --> | |
<nav id="js-menu-content" class="drawer-menu" style="display: none;"> | |
<div class="drawer-menu__container"> | |
<h2 id="js-menu-label" class="drawer-menu__headline" tabindex="-1">メニュー</h2> | |
<ul class="drawer-menu__list"> | |
<li class="drawer-menu__item"> | |
<a class="drawer-menu__link" href="#"> | |
<span class="drawer-menu__en-label">Drawer Menu</span> | |
<span class="drawer-menu__jp-label">ドロワーメニュー</span> | |
</a> | |
</li> | |
<li class="drawer-menu__item"> | |
<a class="drawer-menu__link" href="https://codepen.io/tak-dcxi/pen/VwZbwyg" target="_blank" rel="noreferrer noopener"> | |
<span class="drawer-menu__en-label">Hero Header</span> | |
<span class="drawer-menu__jp-label">ヒーローヘッダー</span> | |
</a> | |
</li> | |
<li class="drawer-menu__item"> | |
<a class="drawer-menu__link" href="https://codepen.io/tak-dcxi/pen/jOEVKEX" target="_blank" rel="noreferrer noopener"> | |
<span class="drawer-menu__en-label">Observe Animation</span> | |
<span class="drawer-menu__jp-label">スクロール連動アニメーション</span> | |
</a> | |
</li> | |
<li class="drawer-menu__item"> | |
<a class="drawer-menu__link" href="https://codepen.io/tak-dcxi/pen/yLaaJYj" target="_blank" rel="noreferrer noopener"> | |
<span class="drawer-menu__en-label">Accordion</span> | |
<span class="drawer-menu__jp-label">アコーディオン</span> | |
</a> | |
</li> | |
<li class="drawer-menu__item"> | |
<a class="drawer-menu__link" href="https://codepen.io/tak-dcxi/pen/vYEyrGJ" target="_blank" rel="noreferrer noopener"> | |
<span class="drawer-menu__en-label">Tab</span> | |
<span class="drawer-menu__jp-label">タブコンポーネント</span> | |
</a> | |
</li> | |
<li class="drawer-menu__item"> | |
<a class="drawer-menu__link" href="https://codepen.io/tak-dcxi/pen/vYXWPvZ" target="_blank" rel="noreferrer noopener"> | |
<span class="drawer-menu__en-label">Form Template</span> | |
<span class="drawer-menu__jp-label">フォームテンプレート</span> | |
</a> | |
</li> | |
</ul> | |
</div> | |
<div class="drawer-menu__overlay"></div> | |
</nav> | |
<!-- /.modal-menu --> | |
</header> | |
<!-- /.website__header --> | |
<main class="website__main" data-inert-target> | |
<article class="article"> | |
<h1 class="article__title">このドロワーメニューについて</h1> | |
<div class="article__sentence"> | |
<p>ユーザビリティおよびにアクセシビリティを意識した自作ドロワーメニューです。</p> | |
</div> | |
<section class="article__section"> | |
<h2 class="article__subtitle">自己チェック</h2> | |
<ul class="article__list"> | |
<li class="article__list-item -checked">メニューが開いている時に背景のスクロールを無効にする</li> | |
<li class="article__list-item -checked">メニュー内のリンクをクリック時にメニューを閉じることができる(非同期遷移のサイトやページ内リンクをメニューに含む場合は必須)</li> | |
<li class="article__list-item -checked">支援技術向けのラベルをボタンとメニュー本体に付与する</li> | |
<li class="article__list-item -checked">メニュー本体とボタンの紐付けを行う(aria-controls)</li> | |
<li class="article__list-item -checked">メニュー本体とボタンの開閉制御を同期する</li> | |
<li class="article__list-item -checked">裏側のコンテンツの読み上げを制御する</li> | |
<li class="article__list-item -checked">裏側のコンテンツを操作対象外にする(inert属性を利用)</li> | |
<li class="article__list-item -checked">メニュー本体をEsc操作で閉じられる</li> | |
<li class="article__list-item -checked">メニューを閉じた時にフォーカスをボタンに当てる</li> | |
<li class="article__list-item -checked">背景固定時のスクロールバー消失によるガタツキを防止する</li> | |
<li class="article__list-item -checked">durationの設定を反映したCSSカスタムプロパティを生成することで、JSのオプションで一括でアニメーションのdurationを変えられるようにする</li> | |
</ul> | |
</section> | |
<section class="article__section"> | |
<h2 class="article__subtitle">課題点</h2> | |
<ul class="article__list"> | |
<li class="article__list-item -not-checked">裏側のコンテンツの読み上げ制御はDOM依存のため要検討</li> | |
<li class="article__list-item -not-checked">自作するよりMicromodal.js使ったほうが良さそう</li> | |
</ul> | |
</section> | |
<section class="article__section"> | |
<h2 class="article__subtitle">参考サイト</h2> | |
<ul class="article__list"> | |
<li class="article__list-item -link"><a class="article__link" href="https://magazine.techcareer.jp/instacart-blog/technology-instacart-blog/6418/" target="_blank" rel="noopener noreferrer">アクセシブルなWebモーダルを作る | techcareer magazine</a></li> | |
<li class="article__list-item -link"><a class="article__link" href="https://www.w3.org/TR/wai-aria-practices-1.1/examples/dialog-modal/dialog.html" target="_blank" rel="noopener noreferrer">Modal Dialog Example | WAI-ARIA Authoring Practices 1.1</a></li> | |
<li class="article__list-item -link"><a class="article__link" href="https://bootstrap-guide.com/components/modal" target="_blank" rel="noopener noreferrer">モーダル~Bootstrap5設置ガイド</a></li> | |
<li class="article__list-item -link"><a class="article__link" href="https://standard.shiftbrain.com/blog/unavailable-inert-regions-and-inert-attribute" target="_blank" rel="noopener noreferrer">UIにおける見えるけど利用できない非活性な領域の実装とinert属性について - シフトブレイン/スタンダードデザインユニット</a></li> | |
</ul> | |
</section> | |
</article> | |
<!-- /.article --> | |
</main> | |
<!-- /.website__main --> | |
</div> | |
<!-- /.website --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.addEventListener("DOMContentLoaded", () => { | |
const menuContent = document.getElementById("js-menu-content"); | |
const menuButton = document.getElementById("js-menu-button"); | |
new ModalMenu(menuContent, menuButton); | |
new PrepareCurrent(menuContent); | |
}); | |
class ModalMenu { | |
constructor(menu, button, options) { | |
this.modalMenu = menu; | |
if (!this.modalMenu) | |
throw TypeError("指定したモーダルメニュー本体のセレクタが見つかりません"); | |
this.menuButton = button; | |
if (!this.menuButton) | |
throw TypeError("指定したメニューボタンのセレクタが見つかりません"); | |
const defaultOptions = { | |
closeTriggerSelector: "[data-menu-close-trigger]", // ボタンとは別にクリック時にメニューを閉じるトリガーとなるセレクタ | |
inertTarget: "[data-inert-target]", // 開いている時はこのセレクタを読み上げ対象外にする | |
labelSelector: "#js-menu-label", // 支援技術向けのメニュー本体のラベルとなるidセレクタ | |
hideLabelSelector: true, //ニューのラベルとなる要素を視覚的に非表示にするか | |
clickLinkToClose: true, // メニュー内のリンクをクリック時にメニューを閉じるか | |
toggleDuration: 500 // メニューの遷移時間 | |
}; | |
const mergedOptions = Object.assign(defaultOptions, options); | |
this.options = mergedOptions; | |
/** | |
* ボタンとは別にメニューを閉じるトリガーとなるセレクタの設定 | |
* メニュー内のリンクをクリック時にメニューを閉じる設定をしている場合はメニュー内のa要素をクリック時にもメニューを閉じる | |
*/ | |
this.closeTrigger = this.options.clickLinkToClose | |
? document.querySelectorAll( | |
`${this.options.closeTriggerSelector}, #${this.modalMenu.getAttribute( | |
"id" | |
)} a` | |
) | |
: document.querySelectorAll(this.options.closeTriggerSelector); | |
/** | |
* メニューのラベルとなるセレクタの設定 | |
*/ | |
this.label = document.querySelector(this.options.labelSelector); | |
if (!this.label) throw TypeError("ラベルとなる見出し要素の指定は必須です"); | |
/** | |
* メニューオープン時に読み上げおよびに対象外にするセレクタの設定 | |
*/ | |
this.inertTarget = document.querySelectorAll(this.options.inertTarget); | |
if (!this.inertTarget.length) | |
throw TypeError("inert対象のセレクタの指定は必須です"); | |
/** | |
* 状態格納で使用する変数 | |
*/ | |
this.isExpanded = false; // メニューの開閉状態を格納する | |
this.scrollAmount; // メニューオープン時のスクロール量を格納する | |
/** | |
* 初期化時に属性を付与する | |
*/ | |
this.prepareAttributes(); | |
/** | |
* イベントリスナーの設定 | |
*/ | |
attachEvent(this.menuButton, "click", this.handleButtonClick.bind(this)); | |
this.closeTrigger.forEach((trigger) => { | |
attachEvent(trigger, "click", this.handleCloseTriggerClick.bind(this)); | |
}); | |
attachEvent(document, "keyup", this.handleKeyup.bind(this)); | |
} | |
prepareAttributes() { | |
this.modalMenu.setAttribute("inert", ""); | |
this.modalMenu.style.display = "none"; | |
this.menuButton.setAttribute( | |
"aria-controls", | |
this.modalMenu.getAttribute("id") | |
); | |
this.menuButton.setAttribute("aria-expanded", false); | |
this.menuButton.setAttribute("aria-haspopup", true); | |
this.label.setAttribute("tabindex", "-1"); | |
document.documentElement.setAttribute("data-modal-menu-opened", false); | |
document.documentElement.style.setProperty( | |
"--menu-toggle-duration", | |
`${this.options.toggleDuration}ms` | |
); | |
/** | |
* ラベル対象にidが含まれていない場合はid属性を付与 | |
*/ | |
if (!this.label.hasAttribute("id")) { | |
const randomId = "aria-label-" + Math.random().toString(32).substring(2); | |
this.label.setAttribute("id", randomId); | |
} | |
const labelId = this.label.getAttribute("id"); | |
/** | |
* ラベル対象を非表示にする設定をしている場合の処理 | |
*/ | |
if (this.options.hideLabelSelector) { | |
const styles = { | |
border: "0", | |
clip: "rect(0 0 0 0)", | |
clipPath: "inset(50%)", | |
height: "1px", | |
margin: "-1px", | |
overflow: "hidden", | |
padding: "0", | |
position: "absolute", | |
whiteSpace: "nowrap", | |
width: "1px" | |
}; | |
Object.keys(styles).forEach((key) => { | |
document.querySelector(this.options.labelSelector).style[key] = | |
styles[key]; | |
}); | |
} | |
this.modalMenu.setAttribute("aria-labelledby", labelId); | |
} | |
handleButtonClick(event) { | |
event.preventDefault; | |
if (!this.isExpanded) { | |
this.open(); | |
} else { | |
this.close(); | |
} | |
} | |
handleCloseTriggerClick(event) { | |
event.preventDefault; | |
this.close(); | |
} | |
handleKeyup(event) { | |
const pressEsc = event.keyCode === 27; | |
if (this.isExpanded && pressEsc) { | |
event.preventDefault; | |
this.close(); | |
} | |
} | |
open() { | |
this.modalMenu.removeAttribute("inert"); | |
this.modalMenu.style.display = ""; | |
this.menuButton.setAttribute("aria-expanded", true); | |
document.documentElement.setAttribute("data-modal-menu-opened", true); | |
this.backfaceFixed(true); | |
this.inertTarget.forEach((element) => { | |
element.setAttribute("inert", ""); | |
}); | |
setTimeout(() => { | |
this.label.focus(); | |
}, 100); | |
this.isExpanded = true; | |
} | |
close() { | |
this.modalMenu.setAttribute("inert", ""); | |
this.menuButton.setAttribute("aria-expanded", false); | |
this.menuButton.setAttribute("inert", ""); | |
document.documentElement.setAttribute("data-modal-menu-opened", false); | |
this.backfaceFixed(); | |
this.inertTarget.forEach((element) => { | |
element.removeAttribute("inert"); | |
}); | |
new Promise((resolve) => { | |
setTimeout(() => { | |
this.modalMenu.style.display = "none"; | |
this.menuButton.removeAttribute("inert"); | |
resolve(); | |
}, this.options.toggleDuration); | |
}).then(() => { | |
this.menuButton.focus(); | |
}); | |
this.isExpanded = false; | |
} | |
backfaceFixed(fixed) { | |
/** | |
* 表示されているスクロールバーとの差分を計測し、背面固定時はその差分body要素にボーダーを生成する | |
*/ | |
const scrollbarWidth = window.innerWidth - document.body.clientWidth; | |
document.body.style.borderRight = fixed | |
? `${scrollbarWidth}px solid transparent` | |
: ""; | |
/** | |
* 背面固定する対象を決定する | |
*/ | |
const scrollingElement = () => { | |
const browser = window.navigator.userAgent.toLowerCase(); | |
// document.scrollingElementが有効なブラウザの場合 | |
if ("scrollingElement" in document) return document.scrollingElement; | |
// document.scrollingElementが無効なiOSの場合はbody要素を | |
if (browser.indexOf("webkit") > 0) return document.body; | |
// その他(IEとか)はhtml要素を | |
return document.documentElement; | |
}; | |
/** | |
* 背面固定時に変数にスクロール量を格納 | |
*/ | |
if (fixed) this.scrollAmount = scrollingElement().scrollTop; | |
/** | |
* CSSで背面を固定 | |
*/ | |
const styles = { | |
height: "100vh", | |
left: "0", | |
overflow: "hidden", | |
position: "fixed", | |
top: `${this.scrollAmount * -1}px`, | |
width: "100vw" | |
}; | |
Object.keys(styles).forEach((key) => { | |
scrollingElement().style[key] = fixed ? styles[key] : ""; | |
}); | |
/** | |
* 背面固定解除時に元の位置にスクロールする | |
*/ | |
if (!fixed) window.scrollTo(0, this.scrollAmount); | |
} | |
} | |
function attachEvent(element, event, handler, options) { | |
element.addEventListener(event, handler, options); | |
return { | |
unsubscribe() { | |
element.removeEventListener(event, handler); | |
} | |
}; | |
} | |
class PrepareCurrent { | |
constructor(root, options) { | |
this.root = root; | |
if (!this.root) return; | |
const defaultOptions = { | |
level: 1, | |
ignoreSelector: ".js-ignore-current" | |
}; | |
const mergedOptions = Object.assign(defaultOptions, options); | |
this.options = mergedOptions; | |
this.targets = Array.from( | |
this.root.querySelectorAll(`a:not(${this.options.ignoreSelector})`) | |
); | |
this.targets.map((target) => { | |
this.setCurrentLocation(target, this.options.level); | |
this.setCurrentPage(target); | |
}); | |
} | |
setCurrentLocation(target, level) { | |
const paths = this.getRootAbsolutePath( | |
this.convertHrefToRootAbsolutePath(target) | |
); | |
const matchedPath = paths.map((path, index) => { | |
if (index <= level - 1) { | |
return `${path}/`; | |
} | |
return null; | |
}); | |
const directories = this.getRootAbsolutePath(window.location.pathname); | |
const matchedDirectory = directories.map((directory, index) => { | |
if (index <= level - 1) { | |
return `${directory}/`; | |
} | |
return null; | |
}); | |
const directory = `/${matchedDirectory.join("")}`; | |
const href = `/${matchedPath.join("")}`; | |
if (href === directory && href !== "//") { | |
target.setAttribute("aria-current", "location"); | |
} | |
} | |
setCurrentPage(target) { | |
const path = this.convertHrefToRootAbsolutePath(target); | |
const locationPathname = window.location.pathname.replace( | |
/index\.html$/, | |
"" | |
); | |
if (path === locationPathname) { | |
target.setAttribute("aria-current", "page"); | |
} | |
} | |
convertHrefToRootAbsolutePath(target) { | |
const absolutePath = | |
target instanceof HTMLElement ? target.href : target.href.baseVal; | |
const protocolHost = `${window.location.protocol}//${window.location.host}`; | |
return absolutePath.replace(protocolHost, "").replace(/index\.html$/, ""); | |
} | |
getRootAbsolutePath(absolutePath) { | |
return absolutePath | |
.replace(/\\/g, "/") | |
.replace(/\/[^/]*$/, "") | |
.slice(1) | |
.split("/"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/stickyfill/2.1.0/stickyfill.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/focus-visible@5.2.0/dist/focus-visible.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/wicg-inert@3.1.0/dist/inert.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Base | |
*/ | |
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; | |
--button-size: 40px; | |
} | |
*, | |
*::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; | |
} | |
.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; | |
} | |
/** | |
* Menu Button Component | |
*/ | |
.menu-button { | |
appearance: none; | |
background-color: var(--base-color); | |
border: none; | |
border-radius: 50%; | |
box-shadow: 0 0 12px rgba(0, 0, 0, 0.15); | |
cursor: pointer; | |
height: 50px; | |
padding: 0; | |
position: relative; | |
transition: background-color 0.3s; | |
width: 50px; | |
&.focus-visible { | |
background-color: var(--gray-color-primary); | |
} | |
@media (hover) { | |
&:hover { | |
background-color: var(--gray-color-primary); | |
} | |
} | |
@media screen and (min-width: 1200px) { | |
height: 60px; | |
width: 60px; | |
} | |
} | |
.menu-button__icon { | |
background-color: var(--white-color-primary); | |
bottom: 0; | |
height: 2px; | |
left: 0; | |
margin: auto; | |
position: absolute; | |
right: 0; | |
top: 0; | |
transition: background-color 0.3s; | |
width: 16px; | |
&::before, | |
&::after { | |
background-color: var(--white-color-primary); | |
content: ""; | |
display: inline-block; | |
height: 100%; | |
left: 0; | |
position: absolute; | |
top: 0; | |
transition: transform 0.3s; | |
width: 100%; | |
} | |
.menu-button[aria-expanded="false"] & { | |
&::before { | |
transform: translateY(-5px); | |
} | |
&::after { | |
transform: translateY(5px); | |
} | |
} | |
.menu-button[aria-expanded="true"] & { | |
background-color: transparent; | |
&::before { | |
background-color: var(--white-color-primary); | |
transform: translateY(0) rotate(45deg); | |
} | |
&::after { | |
background-color: var(--white-color-primary); | |
transform: translateY(0) rotate(-45deg); | |
} | |
} | |
} | |
/** | |
* Website Layout | |
*/ | |
.website__header { | |
position: relative; | |
z-index: 1; | |
} | |
.website__main { | |
overflow-x: hidden; | |
padding: 108px 5%; | |
@media screen and (min-width: 768px) { | |
padding: 120px 5%; | |
} | |
@media screen and (min-width: 1200px) { | |
padding: 160px 5%; | |
} | |
} | |
/** | |
* global-header | |
*/ | |
.global-header { | |
align-items: center; | |
display: flex; | |
justify-content: space-between; | |
left: 0; | |
padding: 0 5%; | |
position: fixed; | |
top: 20px; | |
width: 100vw; | |
z-index: 2; | |
@media screen and (min-width: 768px) { | |
top: 32px; | |
} | |
@media screen and (min-width: 1200px) { | |
top: 40px; | |
} | |
} | |
/** | |
* Modal Menu Component | |
*/ | |
.drawer-menu { | |
height: 100%; | |
left: 0; | |
overflow: hidden; | |
position: fixed; | |
top: 0; | |
width: 100%; | |
z-index: 1; | |
} | |
.drawer-menu__overlay { | |
animation-duration: var(--menu-toggle-duration); | |
animation-fill-mode: forwards; | |
background-color: rgba(0, 0, 0, 0.9); | |
height: 100%; | |
left: 0; | |
position: absolute; | |
top: 0; | |
width: 100%; | |
z-index: -1; | |
[data-modal-menu-opened="true"] & { | |
animation-name: menu-overlay-appeared; | |
} | |
[data-modal-menu-opened="false"] & { | |
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 { | |
display: flex; | |
height: 100%; | |
align-items: center; | |
justify-content: center; | |
flex-direction: column; | |
margin: auto; | |
overflow: hidden; | |
padding: 80px 0; | |
} | |
.drawer-menu__list { | |
list-style: none; | |
margin: 0; | |
overflow-x: hidden; | |
overflow-y: auto; | |
padding: 0; | |
} | |
.drawer-menu__item { | |
position: relative; | |
& + & { | |
margin-top: 2em; | |
} | |
[data-modal-menu-opened="true"] & { | |
animation: menu-item-appeared-first; | |
animation-delay: calc(var(--menu-toggle-duration) - 0.2s); | |
animation-duration: 0.5s; | |
animation-fill-mode: both; | |
animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); | |
&::before { | |
animation-delay: calc(var(--menu-toggle-duration) + 0.3s); | |
animation-duration: var(--menu-toggle-duration); | |
animation-fill-mode: both; | |
animation-name: menu-item-appeared-second; | |
animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1); | |
background-color: var(--gray-color-secondary); | |
content: ""; | |
display: inline-block; | |
height: 100%; | |
left: 0; | |
position: absolute; | |
top: 0; | |
transform-origin: bottom; | |
width: 100%; | |
z-index: 1; | |
} | |
} | |
[data-modal-menu-opened="false"] & { | |
animation-duration: var(--menu-toggle-duration); | |
animation-fill-mode: forwards; | |
animation-name: menu-item-appeared-leaved; | |
} | |
} | |
@keyframes menu-item-appeared-first { | |
0% { | |
transform: translate3d(-100%, 0, 0); | |
} | |
100% { | |
transform: translate3d(0, 0, 0); | |
} | |
} | |
@keyframes menu-item-appeared-second { | |
0% { | |
transform: scale3d(1, 1, 1); | |
} | |
100% { | |
transform: scale3d(1, 0, 1); | |
} | |
} | |
@keyframes menu-item-appeared-leaved { | |
0% { | |
opacity: 1; | |
} | |
100% { | |
opacity: 0; | |
} | |
} | |
.drawer-menu__link { | |
align-items: center; | |
color: inherit; | |
display: block; | |
justify-content: space-between; | |
letter-spacing: 0.01em; | |
padding: 0 1em; | |
position: relative; | |
text-decoration: none; | |
transition: transform 0.3s; | |
&[aria-current] { | |
opacity: 0.5; | |
} | |
&:not([aria-current]):focus { | |
transform: translateX(8px); | |
} | |
@media (hover) { | |
&:not([aria-current]):hover { | |
transform: translateX(8px); | |
} | |
} | |
} | |
.drawer-menu__en-label { | |
color: var(--gray-color-secondary); | |
display: block; | |
font-family: "Montserrat", sans-serif; | |
font-size: 2em; | |
font-weight: 500; | |
text-transform: uppercase; | |
} | |
.drawer-menu__jp-label { | |
color: var(--gray-color-tertiary); | |
display: block; | |
} | |
.drawer-menu__close-button { | |
border-bottom: var(--gray-color-secondary) 1px solid; | |
order: -1; | |
text-align: right; | |
} | |
/** | |
* article module | |
*/ | |
.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; | |
} | |
} | |
} | |
/** | |
* component | |
*/ | |
.logo { | |
font-family: "Lobster", cursive; | |
font-size: 20px; // 拡大しないようにあえてのpx指定 | |
white-space: nowrap; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://fonts.googleapis.com/css2?family=Lobster&family=Montserrat:wght@500&display=swap" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment