ResizeObserverとSpacerでFloating UIがコンテンツを隠すのを防ぐ
position: fixed;を使ったFloating UIは、画面内に常に要素を表示できる一方、ページ下部のコンテンツやボタンを覆い隠してしまうことがある。
あらかじめ固定の余白を確保しておくのもひとつの方法ではあるが、ダイナミックな要素の場合に対応できなかったり、単純にページ下部に余計な余白が生まれてしまったりする。
そこで Spacerコンポーネントを配置し、その高さをResizeObserverで動的に変更する方法をオススメしたい。
※Spacerコンポーネントとは、余白確保のために設置するレイアウト用の空要素のこと。(参考:コンポーネント指向時代のmargin戦略 / Rethinking the relationship between Components and Margins)
よくあるFloating UIがメインコンテンツを隠す例:
<main>
<form>
...
<button type="submit">購入する</button>
</form>
</main>
<aside class="cart-viewer">
<h3>カートの料金</h3>
<p>合計金額: 1000円</p>
<button type="button">カートの詳細を表示する</button>
</aside>
.cart-viewer {
position: fixed;
bottom: 1rem;
right: 1rem;
}
Floating UIがメインコンテンツを隠す例
ここにメインコンテンツが表示される
ResizeObserverを使ってFloating UI分の余白を確保する
Floating UIが固定高ならpadding/marginなどで確保するだけでよいが、カートの詳細表示やバリデーションメッセージなど動的に高さが変わる場合は、固定値では対応がしづらい。そのため、ResizeObserverとSpacerコンポーネントを使う。
メインコンテンツ下部にSpacerコンポーネントを設置し、Floating UI分の高さを確保してページ末尾にスクロールできる余白を追加する。Floating UIの高さが変わったときはResizeObserverで高さを取得して、Spacerの高さを更新する。
<main>
...
<div class="floating-spacer" aria-hidden="true"></div>
</main>
<aside class="cart-viewer">
...
</aside>
.floating-spacer {
/* JavaScriptで更新する */
height: 0;
}
const target = document.querySelector('.cart-viewer');
const spacer = document.querySelector('.floating-spacer');
function updateHeight(entries) {
const height = entries[0].borderBoxSize[0].blockSize;
// height + padding/margin分の余白
spacer.style.height = `${height + 40}px`;
}
// Floating UIの高さが変わったときに、その高さをspacerに反映する
const resizeObserver = new ResizeObserver(updateHeight);
resizeObserver.observe(target);
こうすることで、Floating UIの下に隠れていたコンテンツも、スクロールすれば表示や操作ができるようになる。
ResizeObserverを使ってスクロール分の余白を確保する
ここにメインコンテンツが表示される