[Javascript] スクロールアニメーションのためのトリガー機能

2023年9月30日

Javascript

eyecatch 最近ホームページの制作依頼を仕事で受ける時に、必ず言われるキーワードがあります。 「トップページは、アニメーションで動かして良い感じにして!」 確かに、トリッキーなホームページも世の中に増えてきたし、自分としても、他にあまり無いユニークなホームページを作るのは好きである。

以前作ったライブラリ

2年ほど前にも、ホームページのアニメーションに関するライブラリを作ったので、久しぶりにそのライブラリを引っ張り出して中を確認してみた。 以前ブログ: LPで使いがちな、ページスクロールした時に、文字列が順番にアニメーションするライブラリ作ったよ このライブラリは、テキストのアニメーションを中心に作ったんだけど、これはこれで使えるとして、中のコードが非常に汎用性が乏しい書き方をしていて、エンジニアとして書き直したくなった。 確かに、アニメーションをするだけで、ホームページが生きている感覚が得られる。 でも、ゴリゴリにアニメーションさせるのも悪くないが、シンプルにスクロールに応じてフェードインしたり、スクロールインするようなだけでも、見た目的な面白さを感じられる。

今回のツールの目的

とりあえず、今回は汎用的に末永く使えるライブラリを作ってみたくなり、アニメーションの細かな仕様はcssで構築すればいいので、アニメーションさせたい要素(HTMLタグ)のAttribute(属性)を変更する機能だけを作ってみたいと思います。 スクロールで画面の中に要素が入ってきた時に、フラグがONになると、ONとOFFのときのアニメーションを別途cssで構築しておけばいいという、なんとも汎用性高い仕様です。

ソースコード

trigger.js

class Trigger{ attribute_name = 'data-trigger' attribute_repeat = 'data-repeat' class_flg = 'data-trigger-flg' constructor(){ window.addEventListener('scroll' , this.event_scroll.bind(this)) this.event_scroll() } get num_window_scroll(){ return window.document.scrollingElement.scrollTop } get num_window_height(){ return window.innerHeight } num_elm_scroll(elm){ const rect = elm.getBoundingClientRect() return rect.top } get elm_triggers(){ return document.querySelectorAll(`[${this.attribute_name}]`) } event_scroll(e){ for(const elm of this.elm_triggers){ switch(elm.getAttribute(this.attribute_name)){ case 'upper-in': // 通常スクロールで画面にインした場合 this.scroll_upper_in(elm) break case 'lower-in': // 逆スクロール(したから上)の際に画面にインした場合 this.scroll_lower_in(elm) break case 'in': // 表示画面内に入った場合 this.scroll_in(elm) break case 'out': // 表示画面から外れ場合 this.scroll_out(elm) break case 'rate': // スクロール値(表示画面の領域内) this.scroll_rate(elm) break } } } scroll_in(elm){ const rect = elm.getBoundingClientRect() // 画面上部(下部)からハズレた場合にトリガーフラグを外す if(rect.top + elm.offsetHeight < 0 || rect.top > this.num_window_height){ if(elm.hasAttribute(this.class_flg) && elm.getAttribute(this.attribute_repeat) === 'infinite'){ elm.removeAttribute(this.class_flg) } return } // 画面内に入っている場合にトリガーフラグをセット if(!elm.hasAttribute(this.class_flg)){ elm.setAttribute(this.class_flg , true) } } scroll_upper_in(elm){ } scroll_lower_in(elm){ } scroll_out(elm){ } scroll_rate(elm){ } } switch(document.readyState){ case 'complete': case 'interactive': new Trigger() break default: window.addEventListener('DOMContentLoaded' , (()=>new Trigger())) break }

使い方

基本的にスクロールをするときのアニメーションなので、縦に長いホームページが対象になります。 スクロールで画面に入った時に、アニメーションさせたい対象のタグに次の様に属性をセットします。 # before <div class='box orange'></div> # after <div class='box orange' data-trigger='in' data-repeat='infinite'></div>

data-trigger="in"

今回は、スクロールに入ったときだけを対象にするので、値は"IN"しか処理していません。 ※察しの言い方なら想像がつくと思いますが、OUTや他の色々なトリガーを用意する予定です。

data-repeat="infinite"

この命令は、ページ内で1回だけしか行わないアニメーションであれば、書かなくても大丈夫です。 inifiniteという値にすれば、スクロールを何度しても同じ要素がアニメーションを繰り返します。 何度もアニメするのがウザく感じる場合は、infiniteを無くしてください。 下のデモでは、オレンジ色だけにinfiniteを付けています。スクロールを何度もやって見てみてください。

サンプル

表示するHTMLと、アニメーションを書いたCSSを用意すれば、

sample.html

<div class='sample'> <p data-trigger='in'>Red</p> <section class='s1'> <div class='box red' data-trigger='in'></div> </section> <p data-trigger='in'>Blue</p> <section class='s2'> <div class='box blue' data-trigger='in'></div> </section> <p data-trigger='in' data-repeat='infinite'>Orange</p> <section class='s3' data-trigger='in' data-repeat='infinite'> <div class='box orange' data-trigger='in' data-repeat='infinite'></div> </section> <p data-trigger='in'>Pink</p> <section class='s4'> <div class='box pink' data-trigger='in'></div> </section> <p data-trigger='in'>Yellow</p> <section class='s5'> <div class='box yellow' data-trigger='in'></div> </section> </div>

sample.css

.sample section, .sample section *{ white-space:normal; } .sample section{ height:300px; border:1px solid black; padding:30px; margin:30px; position:relative; } .sample section .box{ width:100px; height:100px; background-color:black; opacity:0; transition-property:opacity; transition-duration:1.0s; transition-delay:0.3s; } .sample section .red{ background-color:red; } .sample section .blue{ background-color:blue; } .sample section .orange{ background-color:orange; } .sample section .pink{ background-color:pink; } .sample section .yellow{ background-color:yellow; } .sample section .yellow{ border:1px solid black; } .sample section [data-trigger-flg]{ opacity:1.0; } .sample p{ margin:0!important; font-size:2.0em; font-weight:bold; transform:translateX(-100%); opacity:0.0; } .sample p[data-trigger='in'][data-trigger-flg='true']{ animation-name:banner-string; animation-duration:0.8s; animation-timing-function : ease; animation-fill-mode:forwards; } @keyframes banner-string{ 100%{ transform:translateX(0); opacity:1.0; } }

デモ

Red

Blue

Orange

Pink

Yellow

あとがき

とりあえず、これだけでもコピペで使えると思ったので、ツールが完成していないけどフライング掲載してみました。 trigger.jsをコピペで作って、独自のcssでアニメーションをセットしたら、ホームページに息吹が組み込まれたようになりますよ。 cssのアニメーションの書き方は、transitionでもkeyframesでも、何でも対応できるので、応用は無限大。 この一手間で、ホームページの質がグッと上がることを知っている人は是非使ってみましょう。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ