以前作ったライブラリ
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
0 件のコメント:
コメントを投稿