これまでページ内のスムーススクロールはJavaScriptを用いて行うのが定石でしたが、CSSの scroll-behavior プロパティ が大半のブラウザで実装済みになりましたので、今後はJSを使わず簡単にできるようになります。
とはいえ JS実装の動きとCSS実装の動きが大きく異なる のでその説明をしたいと思います。そしてそれぞれの特徴を鑑みて、自身にとってどちらが適しているかを判断しましょう。
はじめに
JSのスムーススクロールといっても様々な種類があります。あるものはjQueryライブラリを利用していたり、あるものは移動時の動作が特徴的だったり(特徴的にしてあったり)、など。なので今回サンプルを交えた説明を行うにあたり、弊テンプレートが用いている ネイティブJS(非jQuery)、イージングはeaseOutQuart のものを利用します。
* イージング = 動きの加減速, 動き方の見た目のこと
easeOutQuartは駆け出しは速く、その後緩やかに減速して中間から終点までがおよそ同じ速度になります。
本記事ではscroll-behaviorと何度も書くのは煩わしいので CSSスクロール、JSによるものは JSスクロール と表記します。
JSスクロールとCSSスクロールの比較
JS | CSS | |
---|---|---|
①実装難易度 | 高(ただし通常は テンプレート作者側で設置済) | 低 |
②パフォーマンスへの 影響 | 比較的 高い | 低い |
③除外指定 | 可 | 不可 |
④移動速度(秒数)指定 | 可 | 不可 |
⑤イージング設定 | 可 | 不可 |
⑥ページ遷移後の 頭出しタイミング | 遷移と同時(変更可) | 遷移の直後(変更不可) |
⑦lazyloadとの相性 | 悪い(対策あり) | 悪い(対策あり) |
⑧ページ内画像の width, height属性無し | 到達点が大きくズレる ことがある(対策可) | 到達点が大きくズレる ことがある(対策可) |
⑨遷移先ページ内画像の width, height属性無し | 到達点が大きくズレる ことがある | 到達点がズレたり 全く機能しないことがある (スクロールせずページ最上部を表示) |
⑩ブラウザバック及び フォワード時の挙動 | ページ単位で前後 | ハッシュ(#)付きURLが生成される |
⑪動的要素への適用 | 不可(対応処理可) | 可 |
⑫固定ヘッダーとの 被り制御 | 可 | 可 |
大体こんな感じです。JSの方は動作プログラムなので、大抵のことには対応できます。ただソースコードの作成の難易度が跳ね上がったり、動作が重たくなったり、といったことはありますね。CSSの方はブラウザネイティブなので、ブラウザが定義している動作に準ずるしかありません。
実装サンプル JSとCSSの比較
サンプルを開いて確認してほしいことは以下の通り。
- ページ内のスクロール
- 別ページ遷移後の頭出し(位置合わせ)
- ブラウザバック
メリットやデメリットを見つけやすいのはこの3点かな、と思いますので追って説明します。
ページ内のスクロール
移動に要する秒数
表の④にあたります。JSの方は秒数指定が容易です。CSSの方は指定不可。
で、この『秒数』なんだけれども、移動距離が長くとも短くとも同じ秒数で動作が完了する という点が結構重要です。例えば移動距離、つまり コンテンツの高さ が1,000pxの場合と10,000pxの場合とがあるとして、1,000pxの方は『割とゆっくり移動している』と感じと思います。逆に10,000pxの方は『速い動作でしかもカクつく』といった具体になることが往々にしてあります。何故ならほぼ同じ秒数で動作を完了しようとするからです。カクつく原因の多くは コンテンツ量が多い(縦に長い) 場合や 画像や動画などダウンロードを経て表示される系統のコンテンツが多量に含まれている 場合など。
JSの方は『移動距離いくつに対してコンマ何秒』という形に変更することができます。移動距離1,000pxで1秒ならば、移動距離10,000pxなら10秒かかる、という形ですね。この実装もたまにみかけます。ところが移動に多くの秒数をかけることになってしまうので、好みが分かれるかと思います。通常は前者の『距離に関わらず共通秒数で完了』という実装が多いです。
この『コンテンツが縦に長すぎるとカクつきが〜』についてはJSでもCSSでも同じです。そしてもちろんCSSスクロールでもJSと組み合わせれば秒数指定が可能。でもそれではCSSスクロールを採用する意義が半減してしまいます。JSを使わなくて済むという一番のメリットが消失してしまいますよね。
また、このカクつきは画像がダウンロードされきっていない時にも生じますので、同じページでも画像が完全にダウンロードされた後は発生が抑えられます。
イージング
表の⑤にあたります。JSは指定可、CSSは不可。
CSSスクロールのイージングはブラウザのUAを踏襲 します。ほぼ全て(全ブラウザを検証したわけではないので『ほぼ』)のブラウザが linear という等速イージングを定義されています。JSスクロールの方はイージングを様々にカスタマイズ可能。
JSイージングの方、「ページ最上部へ戻る」をクリックすると最上部到達時になんとなく『減速』を感じることができるかと思います。若干なので気づきにくいですが、車で言うなら「ブレーキの仕方うまいね」と感じるような止まり方(わかりづれぇ)
CSSスクロールでイージングを指定できない点はある人にとってはデメリットになり得ますが、ページ内スクロールの利用は ページが遷移するのではなく滞在ページ中で位置の移動をしていることを示している というのが直感で理解できる、というのが最大の意義です(と私は考えています)。瞬間でパッと移動すると遷移したのか何なのかわかりにくいですよね。そのためのスムーススクロール、と。ならばイージングにそんなにこだわる必要はないのかな、と。
別ページへの遷移直後の頭出し
この章は重要です。
頭出し時の動作
表の⑥にあたります。頭出しのタイミングと挙動について。
JSスクロールの方は、別ページに切り替わると ほぼ同時に 指定位置までの頭出しが行われます。直後、と言っても良いですがスムーススクロールの挙動はありません。FC2ブログで該当を言うと 公式プラグイン『最新コメント』 など。該当のコメントがあるページまで遷移し、加えてそのコメントが記載されている位置まで移動しますよね。
CSSスクロールの方は 遷移先のページが表示されてから スルスルっと目的の位置まで移動します。なので『ページ遷移 + 位置移動』という状況がよりわかりやすくなります。JSスクロールでもこの挙動を実現することは可能です。Facebookなどはかなり前からJSでこの動作を導入しています。ただこの動作に関しては好みがわかれるところかもしれません。
遷移先サンプル(黒背景ページ)には赤い背景を持つ部位を設けてあります。大抵の場合は出発点から終点までの間に何某かの要素が存在していますので、それを赤背景で表現しています。コメントにしてもページ最上部から記事内容を挟んでからコメント、というパターンがほとんどです。赤い部位が記事内容と考えてください。サンプルではJSスクロール・CSSスクロール共に特に問題なく機能しているのが見て取れます。サンプルの場合は赤い部位にテキストも何も無いので とても軽いページですし、スクロールを阻む要因が何も無い 状態です。でも実際にはそうそう上手く運びません。
スクロールと高さの関係
表の⑧にあたります。画像のHTML内容が及ぼす影響について言及します。
ページ内スクロールというのは ページの高さ に大きく関係しています。出発点から到達点までは必ず『距離』の概念があり、それがつまり『高さ』です。間違った日本語で言うなら『縦幅』ですかね。距離が誤認されれば到達点がズレてしまいます。クリックしたら目的の場所までスルーっと移動するはずなのに、途中で止まってしまう、など。恐らく誰しも経験があるのではないでしょうか。
FC2ブログに限定して、一番の位置ズレの原因を言うと 画像の存在 です。あるいは動画でも良いです。例えば画像掲載に以下のようなHTMLを用いた場合
<img src="画像URL" alt>
画像や動画は自身が高さを持っており、各々ダウンロードが完了するまでは高さがゼロとして扱われます。何故かと言えば width, height属性が記されていないから です。
<img src="画像URL" width="600" height="400" alt>
上記のように width属性 及び height属性 が記されている場合は高さの明示がありますのでゼロとしては扱われません。つまりwidth, height属性が プレースホルダー の役割を果たすことができるわけです。画像のダウンロードが完了していない(可視化されていない)状態でも表示領域の確保が行われます。ページ内スクロール利用時は画像の width, height属性記載がとても重要 です。高さを書かないから到達点が狂います。
ところが一時期FC2ブログのエディターではツールを利用して画像掲載した際に、この重要な2属性が書き出されない、という難点がありました。現在は改正されています。
改正前にエディターのツールを利用して画像を掲載したことがある、という方は残念ながら『width, height属性無し画像掲載』が必ずあるはずです。んー、誠に残念ながら ^^;
で、この『位置ズレ』についてはJSでもCSSでも起こります。そしてズレの要因は画像や動画のwidth, height無しだけでなく、例えば到達点までのコンテンツ内にJSで何らかの要素を書き出す、少しだけ専門的な言い方をすると 動的に追加される要素 があり、その構築が遅い場合などもズレます。無かったものが出てきて高さが発生するわけですから当然ズレますね。動的要素は広告もそうですし、FC2ブログに限れば 関連記事 もそうです。
* 動的要素 = 素のHTML(raw HTML)に書かれておらず別のプログラムから出力されるもの
CSSスクロールの動作はブラウザ依存である、というのを大前提に、ページ内スクロールの場合は任意クリックなので今は置いておき、ページ遷移+頭出し の場合のスクロールタイミングについて概ね ページ内コンテンツのダウンロードが完了してから 発動します。あくまでも『概ね』であり、具体的にどのような制御が行われているかは私は不勉強で知らないんですが、ダウンロードが完全に完了していなくてもスクロールが始まることもあります。また、スムーススクロール不能になる 事象も確認しています。スクロール動作が失われて到達点に移動するような感じ、JSと同じような感じになる事象ですね。具体的には『遷移先のページに大量の画像があり、各画像の容量が5000KBを超える大きなものであり、コンテンツ高さが10,000px前後』という極端な場合など。ダウンロードに時間かかってるし、距離が長くなるし、規定秒数での完了が難しいし、といったことが要因です。
JS, CSS共にその極端な条件のサンプルを用意しました。キャッシュの影響なども関係するため、全員が同じ挙動を確認できるわけではありませんが参考として。移動距離が長すぎて全部同じ体感になっているサンプル。
* プライベートモードでのサンプル確認を推奨
JS, CSS共にwidth, height属性無しの方に注目すると、以下のような状況を確認できるかと思います。一瞬なのでハイスペックな環境の方は目視できないかもです。
width, height属性が無い画像は高さがゼロなのですから、本来は随分下の方にあるはずの到達点が見えちゃってますね。ダウンロードが順次行われて各画像がバラバラに高さが発生する。これが レイアウトシフト (Cumulative Layout Shift, CLS) と呼ばれるものでSEO的には減点対象です。
ところで、サンプルでは先ほどから何度も記している『位置ズレ』は確認できなかったのではないでしょうか。次章は位置ズレの可能性がとても高いパターンについてです。
Lazyloadとの共存
表の⑦にあたります。以前から何度か記事にもしていますが、lazyloadとスムーススクロールは非常に相性が悪い という点。
記事内画像のHTMLに loading="lazy" を加えている人がどの程度居るのか不明ですが、ページスピードに敏感な方は書いているかもしれません。
lazyload(lazyloading)というのは 意図的にダウンロードを遅らせる という処理ですから、スムーススクロールがそれこそ円滑なスクロールをする条件に反しています。とは言ってもそれは width, height属性を書かなければ ということです。何度も繰り返しますがこの属性はプレースホルダーになるのですから、書いておけばlazyload画像だとしても高さは確保されます。逆に言うと lazyloadさせる場合はwidth, height属性の記述が必須 です。
* プライベートモードでのサンプル確認を強く推奨
width, height属性なしの方はスクロールに失敗する様子がわかるかと思います(2度目以降はキャッシュの働きで目視できないのでプライベートモードでの閲覧を)
lazyを指定された画像は ユーザーによる任意スクロールが発生しなければダウンロードが行われない のですから、当然ファーストビュー(above the fold)の画像以外は高さゼロです。heightを示唆しなければスムーススクロールは動きもしません。なので共存させたいなら必須属性です。
より万全を期したいのであれば画像をラッパーで包みます。例えば以下のような構文です。
<div style="aspect-ratio: 横幅/高さ; margin: 1em 0;">
<img src="画像URL" width="横幅" height="高さ" alt="代替テキスト" loading="lazy" style="width: 100%; height: 100%; object-fit: cover;">
</div>
記事作成画面で完結させたいなら上記です。スタイルシートを活用するなら
<div class="asp-img-wrapper" style="aspect-ratio: 横幅/高さ;">
<img class="asp-img" src="画像URL" width="横幅" height="高さ" alt="代替テキスト" loading="lazy">
</div>
.asp-img-wrapper {
margin: 1em 0;
}
.asp-img {
width: 100%;
height: 100%;
object-fit: cover;
}
ただしこれだと画像の横幅が記事幅100%取ってしまいますので制限するなら親div要素に
<div class="asp-img-wrapper" style="aspect-ratio: 横幅/高さ; max-width: 最大横幅px">
と max-width プロパティを設けると良いでしょう。
aspect-ratio というプロパティがアスペクト比を固定する役割を担っています。今ほとんどのテンプレートがレスポンシブウェブデザインになっていますけれども、レスポンシブを維持し、レイアウトシフトのストレスを減らすには アスペクト比固定がとても重要 です。
ブラウザの履歴
この章は重要です。
表の⑩にあたります。ブラウザの『バック』『フォワード』の動作に関連します。この項目は 一番最初のサンプル を利用すれば確認可能です。
CSSスクロールのこれが嫌でJSを選択する、という方も少なくありません。例えばAページからBページへ遷移し、Bページ中でページ内スクロールの動作を何度か行ったとします。
ページ最上部
↓
到達点X
↓
到達点Y
↓
到達点Z
と、こんな感じですね。そしてBページ滞在中にブラウザバックの動作を行ったとします。
- JS --- ページAへ
- CSS --- 到達点Yへ
CSSスクロールの方はページが戻るのではなく、直前の到達点にページ内で移動します。CSSスクロールでページAに戻れるのは到達点Yからさらに到達点Xへ移動した後。要はすぐにAページに戻ることはできません。
それぞれの到達点には #ID が記されています。例えば
<h2 id="midashi">見出し</h2>
みたいな感じです。HTML living standard(現在のweb標準規格)ではページ内移動は要素へのid指定で行われます。上記だと #midashi ですね。これがそのままURLとして成立します(してしまいます)ので、
https://sample.html
起点になるBページ、到達点 midashi への移動で
https://sample.html#midashi
CSSスクロールではこの#付きURLを履歴とカウントします。それゆえ ページ単位で戻ったり進んだりができません。記事内にTOC(目次見出し, table of contents)なんかがあって、何度もページ内移動を繰り返したりすると「なんで前のページに戻れないんだよ、ウゼぇ」とかなってしまう可能性がありますね。この点にかなり抵抗を感じる方が居るんじゃないかなぁ。ただ逆にこれが便利と考える方もきっと居るはずなので、一概にデメリットとも言えないかもしれません。ある方にとってのメリットはまたある方のデメリット、逆もまた然り。こういうのは往々にしてあるので個人的好みでありひとつの判断材料になり得るかと思います。
動的追加要素への適用
表の⑪にあたります。CSSは自動的に適用されます。
JSの方はコード内容によりますので一概に言えないけれども、FC2ブログテンプレートの大半は『自動適用不可』です。例えば TOC なんかは良い例です。
当ブログでもTOCコードを提供しています。導入時には弊テンプレートをご利用の場合は自動的にTOCの移動もスムーススクロールの対象になります。他作者様のテンプレートをご利用の方はTOCリンクはスムーススクロールから除外されます。TOCのJSではなくスムーススクロールJSの方をTOC, あるいはその他の動的要素をサポートする形でコード作成する必要があるためです。なので通常のスムーススクロールJSの場合、コード内容を修正(イベントデリゲーション, Event Delegation)するか、TOCその他動的要素個々に専用のスムーススクロールJSを追加する、という対策を取ることになります。
CSSスムーススクロールの場合は全てのハッシュリンク(#付きURL)に対し有効なのでその手間がありません。でも全要素への自動適用を言い換えると 除外も不可能 ということなので(表の③にあたります)、この点も一長一短という感じでしょうか。
まとめ
CSSスクロールの導入を検討する際に問題になりそうな点をまとめてみました。次回申請予定のテンプレートではデフォルトでscroll-behaviorの方を導入してみようと考えています。とはいえこれまでのJSスクロールと使い勝手面でかなり大きな違いがあって戸惑う方も少なくないでしょうから、JSへの切り替えも可能にしておく予定です。
- 『コメント欄のオートリンクを自前で』改正版2024/08/21
- コピペでできる見出しデザインいろいろ2024/02/16
- コピペでできるチャット風吹き出しデザインいろいろ2024/02/08
- コピペでできるテキスト装飾『便箋』と画像装飾『折った紙』2023/12/20
- FC2ブログでJavaScriptを扱う際の注意点2023/06/08
- Google Fontsのバリデートエラーについて2023/05/30
- Chromium系ブラウザでページロード時にtransitionがかかってしまう件の対処2023/05/22
- 『ランキングバナーをどう掲載すれば良いか』続編2023/05/05
管理人のみ閲覧できます
このコメントは管理人のみ閲覧できます