ピュアJavaScriptで
スムーススクロール

ピュアJavaScriptでスムーススクロール_メインビジュアル

プログラム概要

要素のフロート処理と、スムーススクロールの処理を組み合わせたものを、ピュアJavaScriptで制作しました。
任意の位置でフロートさせつつ、上スクロールのときだけ要素を表示させるなど、各種オプション機能を組み込んでいます。また、ヘッダ側に固定表示される要素を登録することで、要素の高さを考慮してスクロール距離が算出されますので、停止位置のズレを気にせずに手軽に済ませることができます。

機能の紹介

フロートの機能
  • フロートのタイミングを、数値または任意の要素のIDで指定
  • ヘッダ側に積み重なるようにフロートさせる
  • 特定の位置に来たらフロートを解除する
  • 上スクロール時だけ表示させる
スムーススクロールの機能
  • アニメーション (easing 関数) の選択
  • スクロール速度の調整
  • 動的要素のサポートの選択
  • ヘッダ側にフロートする要素分のスクロール量の調整
  • イベント発火タイミングをバブリングフェーズ、キャプチャフェーズから選択
各タイミングで付与されるクラス
フロート可能時:is-float_activated
フロート時:is-float_floated
スムーススクロール時:is-scrolled
フロートプログラムのオプション一覧
id フロートさせる要素のID名 ※必須
[ID名]
switchPosition 要素がフロートする位置を指定する
[数値]・[対象のID名]・[null (常時表示)]・[記述無し ( 常時表示)]
stackId ヘッダ側に先行して固定表示されている要素の ID 名を指定すると、その下にツライチとなるタイミングでフロートされる。
[対象の ID 名]・[記述無し]
float 任意のブラウザ幅でフロート要素を活性化するか否かを指定する
– enabled フロートさせるか否か
[true (初期値)]・[false]
– range 適用するブラウザの幅
0番目の要素:[‘max-width’]・[‘min-width’]
1番目の要素:[数値]
[記述無し (常時表示)]
addHeight フロート要素がフロートしているときに、フロートする前の高さを任意の要素に付け足す。
– id [対象の ID 名]
– direction 高さを付け足す方向
[top]・[bottom]
cancel 条件に合致したときにフロートを解除するか否かを指定する
– enabled 指定のブラウザ幅のときに解除するか否か
[true (初期値)]・[false]
– range 適用するブラウザの幅
0番目の要素:[‘max-width’]・[‘min-width’]
1番目の要素:[数値]
[記述無し (常時表示)]
– feature 解除対象のフロート要素が、メインコンテンツ・サイドコンテンツどちらにあるか。
メインコンテンツ:要素が元々あった位置で解除される
サイドコンテンツ:メインコンテンツの下端で解除される
[main]・[side]
cancel – sideOptions feature で [side] を選択時のオプション
– mainId [メインコンテンツの ID 名]
– coordinate イベントが発火する座標を調整するためのパラメータ
[数値]
– absolute side の要素に指定する position absolute の top の座標調を整用するためのパラメータ
[数値]
scrollUp フロート要素が上スクロールのときにだけ表示されるようにする
– enabled 指定のブラウザ幅のときに、上スクロール判定を有効にするか否か。
[true (初期値)]・[false]
– range 適用するブラウザの幅
0番目の要素:[‘max-width’]・[‘min-width’]
1番目の要素:[数値]
[記述無し (常時表示)]
– feature 要素の表示方法
マージンで調整するか、クラスを付与するか。
[changeMargin]・[addClass]
– marginDirection feature で [changeMargin] を選択時に必要
マージンを調整する方向
[top]・[bottom]

フロートプログラムのオプション記入例

var setFloatOptions = function() {
  var floatOptions = [
    {
      id: 'floatHeader',
      switchPosition: 'floatHeader',
      addHeight: {
        id: 'header',
        direction: 'bottom',
      },
    },
    {
      id: 'floatPageLink',
      switchPosition: 'floatPageLink',
      addHeight: {
        id: 'floatPageLinkWrap',
        direction: 'top',
      },
      stackId: 'floatHeader',
    },
    {
      id: 'floatFooter',
      float: {
        enabled: true,
      },
      addHeight: {
        id: 'footer',
        direction: 'bottom',
      },
      scrollUp: [
        {
          range: ['max-width', 767],
          enabled: true,
          feature: 'changeMargin',
          marginDirection: 'bottom',
        },
      ],
      cancel: [
        {
          range: ['max-width', 767],
          enabled: true,
          feature: 'main',
        },
      ],
    },
    {
      id: 'floatToTop',
      switchPosition: 300,
    },
    {
      id: 'floatToFooter',
      switchPosition: 0,
    }
  ];
  floatContent(floatOptions);
};
setFloatOptions();
スムーススクロールプログラムのオプション一覧
easing アニメーションの選択
[linear]・[easeOutExpo]・[easeInQuad]・[easeOutQuad]・[easeInOutQuad]・[easeInSine]・[easeOutSine]・[easeInOutSine]・[easeInCubic]・[easeOutCubic]・[easeInOutCubic]・[記述無し (linear)]
eventUseCapture イベントの発火タイミングを、バブリングフェーズからキャプチャフェーズに変更する。
addEventListener() の第3引数『capture』を[true]にする
[true]・[false]・[記述無し (false)]
duration 移動速度のプロパティ
– anchor リンク先への移動速度
[数値]・[記述無し (1000)]
– urlHash URLハッシュリンクでの移動速度
[数値]・[記述無し (anchorで指定した数値 or 1000)]
dynamic 動的要素対応のプロパティ
– support 動的要素をサポートするか否か
[true]・[false]・[記述無し]
– parentId 動的要素を取得するためのイベントの起点
[id名]・[記述無し]
[記述無し] で初期値の [document] となる
floatTopElem head側にフロートする要素のプロパティ
– id head 側にフロートする要素のID名
[ID名]・[記述無し]
– alwaysFloated 常時フロートしているかどうか
[true]・[false]・[記述無し]
addClass スムーススクロール中に指定要素に [is-scrolled] クラスを付与する
– id [対象の ID 名]
floatStatus フロート要素に付与するクラス名のプロパティ
– floatedClass フロート要素がフロートしているときに付与されるクラス
[class名]・[記述無し (is-float_floated)]
– enabled フロート要素として有効化させたいブラウザ幅のときに付与されるクラス
[class名]・[記述無し (is-float_enabled)]

スムーススクロールプログラムのオプション記入例

var setSmoothScrollOptions = function() {
  var options = {
    easing: 'linear',
    duration: {
      anchor: 600,
      urlHash: 0,
    },
    floatTopElem: [
      {
        id: 'floatHeader',
        alwaysFloated: false,
      },
      {
        id: 'floatPageLink',
        alwaysFloated: false,
      }
    ],
    addClass: {
      id: ['floatFooter', 'floatPageLink'],
    },
    eventUseCapture: false
  };
  smoothScroll(options);
};
setSmoothScrollOptions();

デモページについて

デモページではプルダウンから、スムーススクロール用のアニメーション(easing関数)を変更できます。
また、ヘッダ側にフロートする要素を2つ設けており、どちらも不透明になっていますので、フロートするタイミングやスクロール停止位置にずれがないかを確認できます。
ピュアJavaScriptでスムーススクロール_デモ画像その1

制作について

制作目的
職場で利用しているスクロールスクリプトが、jQueryのよく見かけるシンプルな作りのものでしたので、ページの構成次第では望んだ位置で止まらなかったり、上から下へのスクロールは問題ないのに、下から上にスクロールすると、停止位置がずれる…といったことがあり、どうにかしたいと思いこのスクリプトを制作しました。
動的要素への対応や途中でフロートを解除する機能など、欲しい機能を思いつくたびに、少しずつ改良しています。
苦労したところ
フロート要素にtransitionが掛かっていて、且つ高さが変化するスタイルが対象に含まれている場合、スクロール停止位置に誤差が出てしまうというトラブルで手こずりました。
当時は原因が全く分からず、何故か誤差が出るときと出ないときがあり、一時は諦めていました。
ですが、たまたまtransitionに原因があることを特定でき、高さを取得する際にtransitionを無効にすることで、何とか改善することができました。
開発環境
フロントエンド
言語: HTML5 CSS3, JavaScript
エディタ
Visual Studio Code
製作期間
2018年6月~2019年10月まで随時機能を追加 (計1カ月半ほど)