ヘッダーの高さのように、表示されるまでわからない値をCSSで使いたいときは、JavaScriptで値を取得して、CSSのカスタムプロパティにセットする方法が便利です。
ヘッダーの高さをカスタムプロパティにセットする
// ヘッダーの高さを取得するconst headerElement = document.getElementById("header");const headerHeight = headerElement?.offsetHeight ?? 0;// ヘッダーの高さをカスタムプロパティにセットするdocument.documentElement.style.setProperty("--headerHeight", `${headerHeight}px`);#headerが存在しない場合、headerElementはnullになり、そのままoffsetHeightを参照するとエラーになります。そこで、オプショナルチェーン(?.)(新しいタブで開く)でつなぎます。
その場合、headerElement?.offsetHeightの結果はundefinedになるので、Null合体演算子(??)(新しいタブで開く)で0を代入します。
セットした値は、CSSでvar()を使って参照できます。
main { padding-top: var(--headerHeight);}特定の要素にカスタムプロパティを設定する
document.documentElement(<html>要素)ではなく、特定の要素にセットすることもできます。その要素と子孫の要素だけで使える値になります。
const sectionElement = document.getElementById("section");const sectionHeight = sectionElement?.offsetHeight ?? 0;// セクション要素にカスタムプロパティをセットするsectionElement?.style.setProperty("--sectionHeight", `${sectionHeight}px`);カスタムプロパティの値を取得する
:root { --headerHeight: 60px;}// カスタムプロパティの値を取得するconst headerHeight = getComputedStyle(document.documentElement).getPropertyValue("--headerHeight");console.log(headerHeight); // 60px取得できる値は文字列です。数値として計算に使う場合は、parseFloat(headerHeight)のように変換してください。
Resize Observer APIと組み合わせる
ヘッダーの高さを常に監視する(単一要素)
メニューの開閉などでヘッダーの高さが変わることを想定した処理です。Resize Observer API(新しいタブで開く)を使用して#headerを常に監視し、高さの変化があったら自動的に--headerHeightを更新します。
const resizeTarget = document.getElementById("header");if (resizeTarget) { const resizeObserver = new ResizeObserver((entries) => { // #headerは1つしかないので、entriesの1つ目を取得 const entry = entries[0]; if (entry.borderBoxSize) { const { blockSize } = entry.borderBoxSize[0]; document.documentElement.style.setProperty( "--headerHeight", `${blockSize}px` ); } }); resizeObserver.observe(resizeTarget);}borderBoxSizeは、paddingとborderを含めた大きさです。blockSizeは、横書きのページでは高さにあたります。
セクションの高さを常に監視する(複数要素)
アコーディオンの開閉などで高さが変わるセクションを監視する場合は、セクションが複数あることを想定して、querySelectorAll()を使用すると良いでしょう。その場合は、コールバックに渡されるentriesをループで処理し、それぞれの要素(entry.target)にカスタムプロパティをセットします。
const resizeTargets = document.querySelectorAll(".section");if (resizeTargets.length > 0) { const resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { if (entry.borderBoxSize) { const { blockSize } = entry.borderBoxSize[0]; entry.target.style.setProperty("--sectionHeight", `${blockSize}px`); } } }); resizeTargets.forEach((target) => { resizeObserver.observe(target); });}参考・引用
- CSS カスタムプロパティ(変数)の使用 - CSS | MDN(新しいタブで開く)
- リサイズオブザーバー API - Web API | MDN(新しいタブで開く)
- JavaScriptでHTML要素の高さを取得する方法 - Qiita(新しいタブで開く)
この記事は役に立ちましたか?