
#70 scrollTrigger.jsを試してみる
https://www.willstyle.co.jp/blog/2869/ の記事を見て、難しかったので、写経することで内容を理解しようとした試み。
基礎 ゆっくり表示
まずはCDNの読み込み
<script src="https://cdnjs.cloudflare.com/ajax/libs/ScrollTrigger/1.0.3/ScrollTrigger.min.js"></script>
scrollTrigger.jsを呼び出す
<script>
const trigger = new ScrollTrigger.default()
trigger.add('[data-trigger]')
</script>
HTML側にトリガー(data-trigger)をセット
<p data-trigger>contents1</p>
scrollTrigger.jsの基本的な動きは、見えるようになったら、invisibleクラスが消えてvisibleクラスが付くというもの。
CSSで visibleとinvisibleを設定
.visible, .invisible {
opacity: 0;
transition: opacity .5s ease .5s;
}
.visible {
opacity: 1;
}
中級 HTMLにクラスを付与して、動きをカスタマイズ
下から上にフェードインする動きにします。
HTMLに class="translateY" を追加
<div class="wrapper"><p data-trigger class="translateY">contents1</p></div>
<div class="wrapper"><p data-trigger class="translateY">contents2</p></div>
<div class="wrapper"><p data-trigger class="translateY">contents3</p></div>
CSSでtranslateYに、100px下の位置から、0の位置まで移動するように設定
.visible.translateY,.invisible.translateY {
transform: translateY(100px);
transition: all 0.5s cubic-bezier(0.165, 0.840, 0.440, 1.000) .5s;
}
.visible.translateY {
transform: translateY(0);
}
上級1 表示開始位置をカスタマイズする
見えるタイミングが、ブラウザのどの位置に来てから見えるようにするか、カスタマイズする方法 elementとviewportの数値を調整。0.1ならブラウザ(viewport)の上もしくは下から10%の位置にelementが来たら見えるようになる。
once: trueは1回だけ実行するか、once: falseは何度も実行するか。
const trigger = new ScrollTrigger.default()
trigger.add('[data-trigger]', {
once: false,
offset: {
element: {
x: 0,
y: (trigger, rect, direction) => {
return 0.2 //windowの高さの上下から20%の位置にelementが来たときにトリガーされる
}
},
viewport: {
x: 0,
y: (trigger, frame, direction) => {
return trigger.visible ? 0 : 0.2 //windowの高さの上下から20%の位置
}
}
}
})
上級2 JS側でクラスの付け替えをする
toggleのclassメソッドでinの時にactionクラスを付ける
trigger.add('[data-trigger]', {
once: false,
offset: {
element: {
x: 0,
y: (trigger, rect, direction) => {
return 0.2 //windowの高さの上下から20%の位置にelementが来たときにトリガーされる
}
},
viewport: {
x: 0,
y: (trigger, frame, direction) => {
return trigger.visible ? 0 : 0.2 //windowの高さの上下から20%の位置
}
}
},
toggle: {
class: {
in: ['visible', 'action'], //見えた時に、actionというクラスを付与できる
out: ['invisible'] //表示から外れた時に、invisibleというクラスを付与
}
},
})
上級3 JS側で見えた時に関数を実行して動きをよりカスタマイズする
見えると、一文字ずつ大きさが変わる表現
anime.jsもCDNから読み込む
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.1.0/anime.min.js"></script>
HTMLでdata-triggerに値をセット。 data-trigger="scale"とする。
一文字ずつ分割したいので、分割用に親クラスclass="str__animation"を設定
<div class="wrapper" data-trigger="scale"><p class="str__animation">contents1</p></div>
<div class="wrapper" data-trigger="scale"><p class="str__animation">contents2</p></div>
<div class="wrapper" data-trigger="scale"><p class="str__animation">contents3</p></div>
class="str__animation"の中をspanで分割する
const str_animations = document.querySelectorAll('.str__animation');
if(str_animations.length > 0){
str_animations.forEach(element => {
let set_str = "";
const strs = element.innerText.split("");
if(strs.length > 0){
strs.forEach(str => {
set_str += '<span class="str">' + str + '</span>';
});
}
element.innerHTML = set_str;
});
}
CSS側で、str__animationをflexにして、中のspanをblock化する。
中の<span class="str">の最小の大きさをmin-width: .3rem;にする
.str__animation{
display: flex;
}
.str{
min-width: .3rem;
}
scrollTriggerのcallbackでanime.jsを呼び出し、各種項目を設定
scaleを3から1にすることで大きさを変更
const trigger = new ScrollTrigger.default()
trigger.add('[data-trigger="scale"]', {
once: false,
offset: {
element: {
x: 0,
y: (trigger, rect, direction) => {
return 0.2 //windowの高さの上下から20%の位置にelementが来たときにトリガーされる
}
},
viewport: {
x: 0,
y: (trigger, frame, direction) => {
return trigger.visible ? 0 : 0.2 //windowの高さの上下から20%の位置
}
}
},
toggle: {
class: {
in: ['visible', 'action'], //見えた時に、actionというクラスを付与できる
out: ['invisible'] //表示から外れた時に、invisibleというクラスを付与
},
callback: {
in: (trigger) => {
const strs = trigger.element.querySelectorAll('span');
anime({
targets: strs,
scale:[3,1],
easing: 'easeInOutExpo',
duration: 800,
opacity:[0,1],
delay: function(el, i) { return i * 20 }
});
}
}
},
})
上級4 movingLetter.jsと合わせてみる
↑ のコードと合わせてみます。
<h1 class="wrapper ml7" data-trigger="letter">
<span class="text-wrapper">
<span class="letters">Reality is broken1</span>
</span>
</h1>
<h1 class="wrapper ml7" data-trigger="letter">
<span class="text-wrapper">
<span class="letters">Reality is broken2</span>
</span>
</h1>
<h1 class="wrapper ml7" data-trigger="letter">
<span class="text-wrapper">
<span class="letters">Reality is broken3</span>
</span>
</h1>
CSS
.ml7 {
position: relative;
font-weight: 900;
font-size: 3.7em;
}
.ml7 .text-wrapper {
position: relative;
display: inline-block;
padding-top: 0.2em;
padding-right: 0.05em;
padding-bottom: 0.1em;
overflow: hidden;
}
.ml7 .letter {
transform-origin: 0 100%;
display: inline-block;
line-height: 1em;
}
JS
const letters = document.querySelectorAll('.letters');
if(letters.length > 0){
letters.forEach(element => {
let set_str = "";
const strs = element.innerText.split("");
if(strs.length > 0){
strs.forEach(str => {
set_str += '<span class="letter">' + str + '</span>';
});
}
element.innerHTML = set_str;
});
}
const trigger = new ScrollTrigger.default()
trigger.add('[data-trigger="letter"]', {
once: true,
offset: {
element: {
x: 0,
y: (trigger, rect, direction) => {
return 0.2 //windowの高さの上下から20%の位置にelementが来たときにトリガーされる
}
},
viewport: {
x: 0,
y: (trigger, frame, direction) => {
return trigger.visible ? 0 : 0.2 //windowの高さの上下から20%の位置
}
}
},
toggle: {
callback: {
in: (trigger) => {
anime.timeline({loop: false})
.add({
targets: '.ml7 .letter',
opacity: [0, 1],
translateY: ["1.1em", 0],
translateX: ["0.55em", 0],
translateZ: 0,
rotateZ: [180, 0],
duration: 750,
easing: "easeOutExpo",
delay: (el, i) => 50 * i
});
}
}
},
})
参考
https://github.com/terwanerik/ScrollTrigger
https://terwanerik.github.io/ScrollTrigger/
ヘッダーは伊藤若沖の葡萄双鶏図