/* 初期化処理 ---------------------------------------------- */ window.addEventListener("DOMContentLoaded", () => { initViewport(); setHeaderHeight(); scrollHeaderFixed(); initDrawer(); initSmoothScroll(); }); /* 以下、関数定義のみ ---------------------------------------------- */ /** * 375px以下はviewport固定(375px以下のレスポンシブ対応不要) */ function initViewport() { function switchViewport() { const minWidth = 375; const value = window.outerWidth > minWidth ? "width=device-width,initial-scale=1" : `width=${minWidth}`; const viewport = document.querySelector('meta[name="viewport"]'); if (viewport && viewport.getAttribute("content") !== value) { viewport.setAttribute("content", value); } } window.addEventListener("resize", switchViewport, false); switchViewport(); } /** * ヘッダーの高さをCSS変数に設定する関数 * 要素のリサイズを検知して再取得します。 */ function setHeaderHeight(cssVariableName = "--header-height-gutter") { const header = document.querySelector(".js-header-fixed"); if (!header) return; let headerH = header.clientHeight; document.documentElement.style.setProperty(cssVariableName, headerH + "px"); // 要素のリサイズを監視して再取得 const resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { // ヘッダーの高さを再設定 headerH = entry.target.clientHeight; document.documentElement.style.setProperty( cssVariableName, headerH + "px" ); } }); resizeObserver.observe(header); } /** * scrollでheader固定 */ function scrollHeaderFixed() { const fixedHeader = document.querySelector(".js-header-fixed"); if (!fixedHeader) return; function scrollHandler() { // 一定量スクロールしたら表示 fixedHeader.classList.toggle("is-header-fixed", window.scrollY > 100); } window.addEventListener("scroll", scrollHandler); scrollHandler(); } /** * ドロワーメニュー *
タグとタグを組み合わせて作成 */ function initDrawer() { const drawer = document.getElementById("js-site-drawer"); const openTrigger = document.getElementById("js-site-drawer-open"); const closeTriggers = document.querySelectorAll(".js-site-drawer-close"); const navLinks = drawer.querySelectorAll("a[href*='#']"); // ナビを閉じる関数 function closeDrawer() { drawer.removeAttribute("open"); openTrigger.setAttribute("aria-expanded", "false"); } // details要素の開閉時にaria-expandedを更新 drawer.addEventListener("toggle", () => { const expanded = drawer.hasAttribute("open"); openTrigger.setAttribute("aria-expanded", expanded); }); // クローズトリガーのクリックでメニューを閉じる closeTriggers.forEach((trigger) => { trigger.addEventListener("click", closeDrawer); }); // ページ内リンクのクリック時にメニューを閉じる処理 navLinks.forEach((link) => { link.addEventListener("click", (event) => { const url = new URL(link.href); const targetId = url.hash.substring(1); // ハッシュ部分だけ取得 const targetElement = document.getElementById(targetId); // ターゲットがページ内に存在する場合、0.5秒後にメニューを閉じる if (targetElement) { setTimeout(closeDrawer, 200); } }); }); } /** * ハッシュリンククリック時smooth、 headerガター調整 */ function initSmoothScroll() { const anchorLinks = document.querySelectorAll('a[href*="#"]'); anchorLinks.forEach(_addClickEventListener); // アンカー付きでページ遷移した場合 const urlHash = location.hash; if (urlHash) { const targetElm = document.querySelector(urlHash); window.addEventListener("load", () => { _scrollToTarget(targetElm); }); } // MutationObserverを使って動的に追加されたリンクを監視する const observer = new MutationObserver((mutationsList) => { mutationsList.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if ( node.nodeType === Node.ELEMENT_NODE && node.matches('a[href*="#"]') ) { _addClickEventListener(node); } // 子孫要素もチェック node.querySelectorAll?.('a[href*="#"]').forEach(_addClickEventListener); }); }); }); // aタグにクリックイベントを追加する関数 function _addClickEventListener(link) { link.addEventListener("click", (e) => { const targetElm = document.querySelector(link.hash); if (targetElm) { e.preventDefault(); _scrollToTarget(targetElm); } }); } // 引数のターゲットをもとに画面スクロールする関数 function _scrollToTarget(targetElm, smooth = true) { if (targetElm) { const targetRect = targetElm.getBoundingClientRect().top; let fixGutter = document.querySelector(".js-header-fixed").clientHeight; const targetPos = targetRect + window.scrollY - fixGutter - 30; window.scrollTo({ top: targetPos, behavior: smooth ? "smooth" : "auto", }); } } }