フーノページ



JavaScript画像切り替え

JavaScript、スクロールを戻したときに
ヘッダーを出現させる。










クリックの手間をなくす。


こんにちは、「ふ」です。

今回は冒頭の画像のように、逆方向にスクロールしたときにヘッダーやメニューバーが上から出てくる、というものを作ってみます。
順方向へのスクロール時には、要素は画面上に消えるようにしてあります。そのためページ閲覧の邪魔をすることもありません。Xなどのアプリケーションなどでも使われているUIです。


ハンバーガーボタンをクリックさせる手間もなく、スクロールを戻すだけでメニューバーが表示されるため、ユーザにとってもストレスフリーな仕組みです。
ぜひ実装してみてください。








仕組み。


以下の仕組みを考えました。

・ ヘッダーはposition:fixedで画面上部に固定、transformで非表示にしておく。

・ 画面に出現する/消失するCSSアニメーションを、class名のプロパティとして準備。

・ scroll発生時、現在の位置からスクロールされた方向を判定。判定結果に応じてヘッダー出現/消失のアニメーションを発火させる。

表示させるヘッダーは、スクロール状況に関わらず画面上部に固定させておきます。
なお、初期状態ではtransformで画面外まで移動させ、隠れるようにしておきましょう。

ヘッダーが出たり消えたりするアニメーションを設定しておきます。
アニメーションは、要素にclassを追加することで発火させるようにします。というのも、ユーザが閲覧中はスクロールイベントが頻繁に発生します。そのため別の方法でアニメーションを発火させるとヘッダーはひっきりなしにアニメーションすることになるでしょう。
classを追加することでアニメーションさせる方法であれば、一度アニメーションしたあとは同じclassを追加しても再度アニメーションが発動することはありません。



スクロールイベントが発生した際にはwindow.scrollYでページtopからのスクロール量を取得。
スクロール前の位置より値が小さい場合には逆方向へのスクロールと判定することができ、ヘッダーが出てくるアニメーションを発火させます。逆にwindow.scrollYの値が大きい時には順方向へのスクロールとみなされ、ヘッダーには消えていくアニメーションを発火させるようにします。
スクロール前の位置は、スクロールイベントが発生する度に更新するようにしておきます。




HTMLとCSS。


それではコードを書いていきます。

<body>
<header id = "menu">
</header> 
    
<div class = "contents"></div>
<div class = "contents"></div>
<div class = "contents"></div>
<div class = "contents"></div>
<div class = "contents"></div>
<div class = "contents"></div>

</body>

出たり入ったりするheaderを配置。動きを観察しやすいよう、その下には十分にスクロールするだけのdiv要素を置きました。

   #menu {
        height:25vh;
        background-color:deeppink;
        opacity:0.6;
        
        「「3/* 画面上部に固定 */」」
        position:fixed;
        width:100%;
        top:0;
        
        「「3/* 画面上外側に消しておく */」」
       transform:translateY(-100%);
    }
    
    .contents {
        border:solid 2px #444;
        width:90%;
        height:60vh;
        margin:0 auto;
        margin-top:15vh;
    }

実際の場面ではheaderにボタン要素などを配置する事になるでしょうが、ここでは何も入れてません。高さと幅を指定し、背景色をつけておきました。
デフォルトの位置を作っておきます。position:fixed、top:0として画面上部に固定します。なお初期状態では画面から見えないようにしたいので、translateYで↑方向に100%移動させておきます。
観察用の.contentsについては、テキトーに装飾しておきました。



アニメーションを用意しておく。


「「3/* 画面内に出てくる */」」
.appear {
        animation:appear 0.8s forwards;
    }
    @keyframes appear {
        from {
            transform:translateY(-100%);
        }
        to {
            transform:translateY(0%);
        }
    }
    
「「3/* 画面外に消える */」」
    .disappear {
        animation:disappear 0.8s forwards;
    }
    @keyframes disappear {
        from {
            transform:translateY(0%);
        }
        to {
            transform:translateY(-100%);
        }
    }

ヘッダーが出現/消失するためのアニメーション。先述の通りそれぞれclassのプロパティとして設定しておき、スクロール判定によってヘッダーにclassを追加/削除するようにしておきます。

アニメーションに関するプロパティは、ショートハンドで記述しています。
ここで注意したいこと。アニメーション終了時の状態を決めるanimation-fill-modeプロパティについてですが、これは「forards(終了時の状態を保つ)」に指定しましょう。そうでないとヘッダーが出てくるアニメーションが完了したとき、開始前の出ていない状態に戻ってしまいます。




JavaScriptで方向判定。


JavaScriptです。
スクロール方向を判定し、headerを出し入れする仕組みを実装していきましょう。

const menu = document.getElementById("menu");「「1 ..@1@」」
let iti = 0;「「1 ..@2@」」
window.addEventListener("scroll",in_out);「「1 ..@3@」」
    
function in_out() {
    「「3//スクロール方向で条件分岐」」「「1 ..@4@」」
    if(iti < window.scrollY) {
        「「3//classの削除と追加」」「「1 ..@5@」」
        menu.classList.remove("disappear");
        menu.classList.add("appear");
    } else {
        menu.classList.remove("appear");
        menu.classList.add("disappear");
    }
    iti = window.scrollY;「「1 ..@6@」」
}

@1@ header要素を取得。

@2@ 現在のY方向のスクロール位置を入れておく、変数「iti」を作ります。ユーザがページを開いた瞬間は全くスクロールされていないので、初期値0をとしておきます。

@3@ windowオブジェクト、つまりページ全体に対してスクロールのイベントハンドラを設定。第2引数であるin_out関数の内容はこのあと記述します。

以下、スクロール方向を判別してheaderの出し入れをさせるin_out関数です。

@4@ window.scrollY( )メソッドは、現在のスクロール位置を返します。
スクロール直前の位置は変数「iti」に代入しています。scrollYの値がitiより大きければ順方向へのスクロール、逆に小さくなれば逆方向へのスクロールと判断できます。

@5@ 方向判定の結果に応じて、ヘッダーに出し入れのアニメーションを含むclassを付与するようにします。逆アニメーションのclassがすでに付与されている場合にはremove(削除)するようにもしています。

@6@ スクロールイベント完了後、現在位置である変数itiの値を更新します。これで次回スクロールイベントが起こったとき、scrollYと比較してその方向を判別することが可能になります。



結果⬆︎(実際にスクロールしてみてください)。
ひとまづは実装できました。が、少し問題があります。

というのも、ユーザが初めて下にスクロールしたとき。.disapperのアニメーションが発火するため、headerが一瞬画面内に表示されてしまうのです。
これは少し目障り。

<header id = "menu" class = "「「1disappear」」">
</header>

ということで、headerにはあらかじめclass「disappear」を指定しておきましょう。こうすることによって、ページロード時にheaderは画面外に消えていきます。

あらかじめdisappearのアニメーションを発火させておくことで、初回スクロール時に目障りなアニメーションが発生することもなくなりました。



なるべくスクロールのみで。


最後までお読みくださり、ありがとうございました。

スクロールの方向によってメニューなどが含まれたヘッダーを出し入れさせる。スマホなどの狭い画面を圧迫することもなく、またmenuボタンをタップさせる手間を掛けさせない、というメリットがあります。
スクロール自体はユーザに容認されているアクションであるため、今後はこういったものが主流となってくるのではないでしょうか。
サイトの回遊率向上のためにも、ユーザに極力、ストレスを与えないUIを目指していきましょう。

ではまた〜 🎵




「ふ」です。

ふ

ベクターグラフィック、web、ガジェットなど。役立つ情報や観ていてたのしいページを書いていきたいと思います。