【CSS / JS】 今後のスムーススクロールについて
ページ内のアンカーに飛ぶ際、シュルシュルーと画面がスクロールして目的の場所までスクロールしてくれる『スムーススクロール』は色んなサイトで使われているのでよく目にすると思います。
従来の実装は JavaScript でしていたわけですが、CSS だけでも実装できるようになったようです。
html {
scroll-behavior: smooth;
}
少し前から知ってはいたのですが、クロスブラウザ対応を考慮するとSafari とIE に未対応なので実務には使えないものでした。
2022 年に Safari対応、同年 IE のサポートが終了したため使用可能になったわけですね。
今年は2023年ですが、まだあまり見かけないようです。新しいものなのでこれから徐々に増えるのかもしれませんが、調べてみたところいくつか問題点がありました。
問題点
スクロールスピードが調節できない。
イージングが効かない。
サイト内すべてのアンカーがスムーススクロールになる。
他のページから飛んできた際、一旦ページトップへ飛び、そこからスムーススクロールになる。
移動するたびに履歴が残る。( URL の#が切り替わり、ブラウザバックで戻れるようになる。)
『スクロールスピードが調節できない。』『イージングが効かない。』この2点について、将来細かく設定できるような実装があるかもしれません。現状使うのであれば、「デフォルトで大丈夫なら。。」ってところでしょうか。
また、『サイト内すべてのアンカーがスムーススクロールになる。』について、 jQuery で対応できました。そもそも「だったら最初から jQuery で書けばいいのでは?」というのはなしは無しでお願いします。
// 一部アンカーリンクを外す
$('.js_stop_smooth').on('click', function () {
$('html').css({ 'scroll-behavior': 'auto' });
setTimeout(function () {
$('html').css({ 'scroll-behavior': 'smooth' });
}, 1);
});
上記は「 .js_stop_smooth 」 がついているリンクをクリックした場合、一瞬「 'scroll-behavior': 'auto' 」に変更し、即座に「 'scroll-behavior': 'smooth' 」に戻す。といった手順で特定のアンカーだけスムーススクロールを切ることができました。
同じように、『他のページから飛んできた際、ページトップからスムーススクロールになる。』これに対応するには、下記のように書くことで回避できました。
$(function () {
// アンカー付きリンク
$('html').css({ 'scroll-behavior': 'smooth' });
});
『移動するたびに履歴が残る。』に関しては、変えられないというだけで間違った挙動ではないのですが、あまり馴染みがないので無効化にしたかったができませんでした。
現状 JavaScript でうまくいってるのに CSS で実装する理由
簡単なページで他の JavaScript がない場合、jQuery を読み込まなくても実装可能であるため、軽くなることです。
しかしそのような軽いサイトであればあまり重さは気にならないので使う理由も薄いような気もします。
ではなぜ CSS で実装するのか。
何かあるだろうと思い調べていると、便利そうなプロパティが見つかりました。
scroll-padding-top、scroll-margin-top というプロパティですが、
以前 scroll-snap と一緒に使われているのを見たことはあったのですが、アンカーリンクでも効くんですね。
どういうことかというと、画面上部に追従するヘッダーがある場合、アンカーリンクの飛び先を本来の位置よりヘッダの高さ分だけ上げなくてはなりません。
jQuery で実装する場合、飛び先の要素に対してヘッダの高さ分 padding-top とネガティブ margin-top で調整してきたのですが、CSS で実装する場合はhtml に scroll-padding-top をヘッダの高さ分だけ指定すればすべてのアンカーリンクが自動で調整されます。
また、個別で調整する場合はアンカー先の要素に scroll-margin-top を設定することで対応できます。例えば一律でヘッダの高さ分 scroll-padding-top で上にずらし、一部のセクションでは装飾が少し上に飛び出していたとしたら、その分を個別に scroll-margin-top で調整できるんです。
つまり scroll-behavior:smooth を使うことで、scroll-padding-top 、scroll-margin-top が使えるため、従来の jQuery での実装よりコーディングが楽にできるというメリットがあるわけです。
scroll-behavior: smooth を使うべきなのか?
個人的には、scroll-behavior:smooth ではまだ細かい設定ができないため、急いで移行する必要はないように感じました。
しかし scroll-padding-top 、scroll-margin-top は大変便利なので是非導入したいと思ったので、普段使っているjQueryの記述に組み込むことにしました。
$('a[href^=#]').click(function () {
var speed = 500;
var href = $(this).attr("href");
var target = $(href == "#" || href == "" ? 'html' : href);
var position = target.offset().top;
$("html, body").animate({
scrollTop: position
}, speed, "swing");
return false;
});
従来はこんな感じでした。
長らくアップデートしてなかったので、一旦下記のように書き換えます。
$('a[href^=#]').click(function () {
const speed = 500;
const href = $(this).attr('href');
const target = $(href == '#' || href == '' ? 'html' : href);
// スクロール先
const position = target.offset().top;
$('html, body').animate({
scrollTop: position
}, speed, 'swing');
return false;
});
scroll-padding-top 、scroll-margin-top に対応させる。
$('a[href^="#"]').on('click', function () {
const speed = 500;
const easing = 'swing';
const href = $(this).attr('href');
const target = $(href == '#' || href == '' ? 'html' : href);
const spt = parseInt($('html').css('scrollPaddingTop')) || 0;
const smt = parseInt($(target).css('scrollMarginTop')) || 0;
// スクロール先
const position = target.offset().top - (spt + smt);
$('html, body').animate({ scrollTop: position }, speed, easing);
return false;
});
実際コードを走らせてみて気づいたのですが、scroll-margin-topなどをcss()で取得すると計算した値がpxで取れるようです。
そのおかげでcalcを使ったり、remや%で指定されていても対応できてるわけですね。
また、scroll-margin-topに負の数を設定ことでスクロール位置を下にずらすこともできるようです。
結論
今後 scroll-padding-top 、scroll-margin-top を設定しておけば要素ごとにアンカー位置を対応する必要がなくなります。
今後しばらくは jQuery で実装すればよいですね。毎回要素ごとにパディングとネガティブマージンを設定する手間をかけなくて良くなりそうです。
■お仕事のご依頼やご相談はお気軽に
エイトビーは、Web制作会社としてテクノロジーとクリエイティブの融合で最適なコミュニケーションを提案・創造し、お客さまやユーザーの皆さま、すべての人が幸せになれることを目指しています。
■採用募集はこちら
エイトビーでは、新しい仲間を募集しています。
この記事が気に入ったらサポートをしてみませんか?