まずはじめに
ヘッダー部分に追従要素がある時、ページ内スクロールをすると、その追従要素が重なってくることがあると思います。
それをcssと少しのJavaScriptで解決しようという話です。
どう解決するか
cssだけでスムーズスクロールとスクロールした時の余白を設定できるようになりました。
scroll-behavior
https://developer.mozilla.org/ja/docs/Web/CSS/scroll-behavior
scroll-padding-top
https://developer.mozilla.org/ja/docs/Web/CSS/scroll-padding-top
これらを使って解決しようと思います。
<div id="content" class="content">
<nav id="nav" class="nav">
<a href="#target1" class="nav_link">link1</a>
<a href="#target2" class="nav_link">link2</a>
<a href="#target3" class="nav_link">link3</a>
<a href="#target4" class="nav_link">link4</a>
</nav>
<div class="body">
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos adipisci pariatur ut vel harum fugit esse, beatae blanditiis consequuntur velit quisquam magni facere incidunt voluptatem natus. Dolores rerum voluptas aliquam!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus libero assumenda quibusdam rem, neque ullam consectetur expedita exercitationem aliquid accusamus iusto dolore tempore deleniti non cupiditate officia! Esse, non fuga!</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptas ipsum itaque illum dolore hic atque, ducimus quisquam tempora nobis neque, nostrum voluptate eius! Modi, vitae? Quas quaerat unde praesentium neque.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit similique, nobis iste corrupti illo voluptate obcaecati illum praesentium doloremque eaque maiores magnam earum, fuga doloribus adipisci beatae excepturi. Ducimus, ea?</p>
<p id="target1">Anchor Target1</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Molestiae veniam quae enim harum magni cupiditate ipsum atque porro, fugit corporis ab id architecto dolorem quis. Officiis non animi numquam magni!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatem error, explicabo minus officia vero facere officiis voluptatibus et rerum fugit, quia est consectetur, illum cupiditate. In at voluptate voluptatem repudiandae!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eos adipisci pariatur ut vel harum fugit esse, beatae blanditiis consequuntur velit quisquam magni facere incidunt voluptatem natus. Dolores rerum voluptas aliquam!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus libero assumenda quibusdam rem, neque ullam consectetur expedita exercitationem aliquid accusamus iusto dolore tempore deleniti non cupiditate officia! Esse, non fuga!</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptas ipsum itaque illum dolore hic atque, ducimus quisquam tempora nobis neque, nostrum voluptate eius! Modi, vitae? Quas quaerat unde praesentium neque.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit similique, nobis iste corrupti illo voluptate obcaecati illum praesentium doloremque eaque maiores magnam earum, fuga doloribus adipisci beatae excepturi. Ducimus, ea?</p>
<p id="target2">Anchor Target2</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Molestiae veniam quae enim harum magni cupiditate ipsum atque porro, fugit corporis ab id architecto dolorem quis. Officiis non animi numquam magni!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatem error, explicabo minus officia vero facere officiis voluptatibus et rerum fugit, quia est consectetur, illum cupiditate. In at voluptate voluptatem repudiandae!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus libero assumenda quibusdam rem, neque ullam consectetur expedita exercitationem aliquid accusamus iusto dolore tempore deleniti non cupiditate officia! Esse, non fuga!</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptas ipsum itaque illum dolore hic atque, ducimus quisquam tempora nobis neque, nostrum voluptate eius! Modi, vitae? Quas quaerat unde praesentium neque.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit similique, nobis iste corrupti illo voluptate obcaecati illum praesentium doloremque eaque maiores magnam earum, fuga doloribus adipisci beatae excepturi. Ducimus, ea?</p>
<p id="target3">Anchor Target3</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Molestiae veniam quae enim harum magni cupiditate ipsum atque porro, fugit corporis ab id architecto dolorem quis. Officiis non animi numquam magni!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatem error, explicabo minus officia vero facere officiis voluptatibus et rerum fugit, quia est consectetur, illum cupiditate. In at voluptate voluptatem repudiandae!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus libero assumenda quibusdam rem, neque ullam consectetur expedita exercitationem aliquid accusamus iusto dolore tempore deleniti non cupiditate officia! Esse, non fuga!</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptas ipsum itaque illum dolore hic atque, ducimus quisquam tempora nobis neque, nostrum voluptate eius! Modi, vitae? Quas quaerat unde praesentium neque.</p>
<p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit similique, nobis iste corrupti illo voluptate obcaecati illum praesentium doloremque eaque maiores magnam earum, fuga doloribus adipisci beatae excepturi. Ducimus, ea?</p>
<p id="target4">Anchor Target4</p>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Molestiae veniam quae enim harum magni cupiditate ipsum atque porro, fugit corporis ab id architecto dolorem quis. Officiis non animi numquam magni!</p>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatem error, explicabo minus officia vero facere officiis voluptatibus et rerum fugit, quia est consectetur, illum cupiditate. In at voluptate voluptatem repudiandae!</p>
</div>
.content {
width: 300px;
height: 200px;
overflow: hidden auto;
scroll-behavior: smooth;
scroll-padding-top: 40px; // .navの高さが40pxであると想定して決め打ち
}
.nav {
box-sizing: border-box;
display: flex;
align-items: stretch;
justify-content: space-between;
position: sticky;
top: 0;
left: 0;
width: 100%;
padding: 8px;
background-color: #fff;
box-shadow: 0 0 6px 0 rgba(0,0,0,0.5);
}
.nav_link {
color: #06c;
}
上記コードで作ったサンプルです。
※埋め込んだCodepenだとうまく追従してなさそうなので、リンクも貼っておきます。
https://codepen.io/yamabero/full/KwKGwbO
See the Pen scroll in overflow with fixedHeader(css only) by yamabero (@yamabero) on CodePen.
この状態でも、ほぼやりたいことはできてます。
しかしcssだと固定値しか入れられないので、もし追従要素の高さが変わった場合に対応できなくなります。
css変数とJavaScriptで値を上書きする
scroll-padding-top
に入れる値をcss変数に変更します。
.content {
--scrollPadding: 40px;
width: 300px;
height: 200px;
overflow: hidden auto;
scroll-behavior: smooth;
scroll-padding-top: var(--scrollPadding);
}
.nav {
box-sizing: border-box;
display: flex;
align-items: stretch;
justify-content: space-between;
position: sticky;
top: 0;
left: 0;
width: 100%;
padding: 8px;
background-color: #fff;
box-shadow: 0 0 6px 0 rgba(0,0,0,0.5);
}
.nav_link {
color: #06c;
}
その後、JavaScriptのsetProperty
を使って、追従要素の高さで上書きします。
// 追従要素
const nav = document.getElementById('nav');
// スクロール要素
const content = document.getElementById('content');
// 追従要素の高さを取得
const navHeight = nav.offsetHeight;
// スクロール要素のcss変数`--scrollPadding`を追従要素の高さでセット
content.style.setProperty('--scrollPadding', navHeight + 'px' );
こうすることで、もし追従要素内の高さが変わったとしても対応できました。
上記コードで作ったサンプルです。
※埋め込んだCodepenだとうまく追従してなさそうなので、リンクも貼っておきます。
https://codepen.io/yamabero/full/dPygPPX
See the Pen scroll in overflow with fixedHeader by yamabero (@yamabero) on CodePen.
このJavaScriptのコードだと、描画時にしか対応できてないので、何かイベントを実行した時に再取得するようにすれば、応用が効くかなと思います。