コンテンツにスキップ

スクラブ機能

scrub オプションを有効にすれば、トリガー要素がビューポートに入ってから出るまでの進行度が管理され、パララックスなどのスクラブアニメーションを作成することができます。

main.js
new Rola("[data-rola-trigger]", {
scrub: true,
});

なお、特定のトリガー要素のみ scrub オプションを有効にしたい場合は、トリガー要素に data-rola-scrub 属性を指定します。

index.html
<!-- scrub を 有効化 -->
<div data-rola-trigger data-rola-scrub>...</div>
<div data-rola-trigge data-rola-scrub="true">...</div>
<!-- scrub を 無効化 -->
<div data-rola-trigger data-rola-scrub="false">...</div>

これにより、トリガー要素がビューポートの下から入り、上に出るまでの進行度を --rola-progress カスタムプロパティから取得できます。

アニメーション用のCSS

スクラブアニメーション用のCSSは、--rola-progress カスタムプロパティを活用して自由に作成できます。

--rola-progress カスタムプロパティは、トリガー要素のビューポート内のスクロール進行度に応じて 0(ビューポートの下部) ~ 1 (スクラブアニメーションの終了)に変化します。

デフォルトでは、トリガー要素の上部がビューポートの下部に入った時に 0 となり、 トリガー要素の下部がビューポートの上部に辿り着いた時に 1 となります。

なお、rola.css には、あらかじめ フェード などのよく使うであろうアニメーションを用意しています。

--rola-progress を活用し、進行度に応じて任意な値になるようなスタイルを作成します。

--rola-progress01 の数値が提供されるため、opcaityscale のように数値を直接受け入れるプロパティにはそのまま使えます。 また、calc() などと組み合わせることで自由な値や単位に変換できるため、アイデア次第で自由なスクラブアニメーションを作成できます。

例えば、以下のようなCSSを用意します。

style.css
@media (prefers-reduced-motion: no-preference) {
.rola-scrub-fade-in {
opacity: var(--rola-progress, 0);
}
.rola-scrub-translate-x,
.rola-scrub-translate-y {
--scrub-value: calc(var(--scrub-start) * (1 - var(--rola-progress, 0) * var(--depth, 1)) + var(--scrub-end) * (var(--rola-progress, 0) * var(--depth, 1)));
}
.rola-scrub-translate-x {
--scrub-start: 0%;
--scrub-end: calc(100vi - 100%);
translate: var(--scrub-value);
}
.rola-scrub-translate-y {
--scrub-start: 300px;
--scrub-end: 0px;
translate: 0 var(--scrub-value);
}
.rola-scrub-clip-in {
clip-path: inset(calc(30% * (1 - var(--rola-progress, 0))));
}
.rola-scrub-text-clip-in {
color: transparent;
background-image: linear-gradient(90deg, var(--scrub-color-end, #000) 50%, var(--scrub-color-start, #ccc) 50%, var(--scrub-color-start, #ccc) 100%);
background-position: calc(100% * (1 - var(--rola-progress, 0))) 0;
background-clip: text;
background-size: 200% 100%;
}
}

これで、以下のようなHTMLを準備し、Rolaをインスタンス化するとスクラブアニメーションが可能です。

index.html
<p class="rola-scrub-text-clip-in text-large" data-rola-trigger>
Rola is a scroll manager.
</p>
<figure class="sticky" data-rola-trigger>
<img src="pizza.webp" class="rola-scrub-translate-y sticky-image" width="1384" height="924" alt="石窯から出てきたばかりの焼きたてマルゲリータ" decoding="async" loading="lazy">
</figure>
main.js
new Rola("[data-rola-trigger]", {
scrub: true
});

進捗管理の開始と終了

Rolaのスクラブ機能のデフォルトは、トリガー要素の上部がビューポートの下部に入った時に 0 となり、 トリガー要素の下部がビューポートの上部に辿り着いた時に 1 となります。

進捗管理を開始するタイミングと終了するタイミングは、トリガー要素に data-rola-scrub-start 属性と、data-rola-scrub-end 属性を使うことで変更できます。

属性値は、要素の基準点 ビューポートの基準点を、それぞれ パーセンテージ、または top0%と同じ)、center50%と同じ)、bottom100%と同じ) で指定します。 値が1つの場合は、要素の基準点 として扱われ、ビューポートの基準点は、data-rola-scrub-start 属性の場合は、bottomdata-rola-scrub-end 属性の場合は、top が指定されます。

data-rola-scrub-start 属性に指定した 2 つの基準点が交差した位置から進捗管理が開始し、data-rola-scrub-end 属性に指定した 2 つの基準点が交差した位置で進捗管理が終了します。

<p class="rola-scrub-text-clip-in text-large" data-rola-trigger data-rola-scrub-start="bottom" data-rola-scrub-end="top center">
Rola is a scroll manager.
</p>
<figure class="sticky" data-rola-trigger data-rola-scrub-start="0% 0%">
<img src="pizza.webp" class="rola-scrub-translate-y sticky-image" width="1384" height="924" alt="石窯から出てきたばかりの焼きたてマルゲリータ" decoding="async" loading="lazy">
</figure>

例えば上記の例では、p要素には data-rola-scrub-start 属性に bottom が指定されています。 値がひとつのため、ビューポートの基準点は規定値の bottom となります

この場合、トリガー要素の下の辺が、ビューポートの下の位置を交差した時に --rola-progress0 となります。

そして、data-rola-scrub-end 属性に top center が指定されているため、トリガー要素の上の辺がビューポートの垂直中央の位置を交差した時に --rola-progress1 になります。

figure要素は data-rola-scrub-start 属性に 0% 0% が指定されています。

従って、トリガー要素の上の辺が、ビューポートの上の位置を交差した時に --rola-progress0 となります。

data-rola-scrub-end 属性は、指定されていないため、規定値の bottom top となり、トリガー要素の下の辺がビューポートの上の位置を交差した時に --rola-progress1 になります。

ダイナミックイージング

velocityCustomProperty オプションを有効にすると、ターゲット要素に、スクロールの速さを計算するのに便利な値(前回のスクロールと今回のスクロールの差の絶対値)を --rola-velocity カスタムプロパティで提供します。

main.js
new Rola("[data-rola-trigger]", {
velocityCustomProperty: true
});

なお、特定のトリガー要素のみ velocityCustomProperty オプションを有効にしたい場合は、トリガー要素に data-rola-velocity 属性を指定します。

index.html
<!-- velocityCustomProperty を 有効化 -->
<div class="rola-fade-in" data-rola-trigger data-rola-velocity>...</div>
<div class="rola-fade-in" data-rola-trigger data-rola-velocity="true">...</div>
<!-- velocityCustomProperty を 無効化 -->
<div class="rola-fade-in" data-rola-trigger data-rola-velocity="false">...</div>

このカスタムプロパティを活用して、スクロールの速さに応じたダイナミックなイージングを作ることが可能です。

例えば以下のようなCSSを用意するといいでしょう。

style.css
@media (prefers-reduced-motion: no-preference) {
.rola-dynamic-easing {
--dynamic-easing: cubic-bezier(calc(0.25 + var(--rola-velocity, 0) * 0.1), calc(1 - var(--rola-velocity, 0) * 0.2), calc(0.5 + var(--rola-velocity, 0) * 0.1), 1);
--dynamic-duration: calc((1 + var(--rola-velocity, 0)) * 0.6s);
transition: var(--dynamic-property, none) var(--dynamic-duration) var(--dynamic-easing);
}
.rola-scrub-translate-x,
.rola-scrub-translate-y {
--scrub-value: calc(var(--scrub-start) * (1 - var(--rola-progress, 0) * var(--depth, 1)) + var(--scrub-end) * (var(--rola-progress, 0) * var(--depth, 1)));
&.rola-dynamic-easing {
--dynamic-property: translate;
}
}
.rola-scrub-text-clip-in {
color: transparent;
background-image: linear-gradient(90deg, var(--scrub-color-end, #000) 50%, var(--scrub-color-start, #ccc) 50%, var(--scrub-color-start, #ccc) 100%);
background-position: calc(100% * (1 - var(--rola-progress, 0))) 0;
background-clip: text;
background-size: 200% 100%;
&.rola-dynamic-easing {
--dynamic-property: background-position;
}
}
}
index.html
<p class="rola-scrub-text-clip-in rola-dynamic-easing text-large" data-rola-trigger data-rola-velocity data-rola-scrub-start="bottom" data-rola-scrub-end="top 50%">
Rola is a scroll manager.
</p>
<figure class="sticky" data-rola-trigger data-rola-velocity>
<img src="pizza.webp" class="rola-scrub-translate-y rola-dynamic-easing sticky-image" width="1384" height="924" alt="石窯から出てきたばかりの焼きたてマルゲリータ" decoding="async" loading="lazy">
</figure>

ビューポートのマージン

rootMargin オプションを使えば、data-rola-inview 属性の値( true / false )が切り替わるタイミングや、進行度を管理するタイミングをコントロールできます。初期値は 0px となっており、ビューポート内に要素が少しでも入ったら data-rola-inview 属性が true になります。

rootMarginIntersectionObserverrootMargin オプションと同等で CSSの margin プロパティのように設定します。

main.js
new Rola("[data-rola-trigger]", {
rootMargin: "0px 0px -30%"
});

上記の例では、ビューポートの1番上から、下から 30% までのエリアにトリガー要素が入った時に data-rola-inview 属性が true になります。

ターゲット要素の変更

デフォルトでは、トリガー要素に data-rola-inview 属性や、--rola-progress カスタムプロパティが付与されますが、時にはトリガー要素ではない要素をアニメーションしたい場合などもあります。その場合は トリガー要素に data-rola-target属性を使い、 data-rola-inview 属性や、--rola-progress カスタムプロパティを付与させたい要素(ターゲット要素)を CSSセレクタで指定します。

index.html
<div data-rola-trigger data-rola-target="#target">...</div>
...
<div id="target" class="rola-scrub-translate-y">...</div>

これにより、トリガー要素がビューポートに入ったら、ターゲット要素のdata-rola-inview 属性が true になり、--rola-progress カスタムプロパティによる進行管理が始まります。

JavaScriptによる操作

Rola は、インスタンス作成時の第3引数にコールバック関数を持たせることができます。

scrub オプションが有効時のコールバック関数はビューポート内でスクロール値が更新されるたびに実行されます。 なお、once オプションが有効な場合には、最初にビューポートに入ったタイミングで1度だけ実行されます。

main.js
const callback = (element, isInView, options, progress) => {
if (isInView) {
console.log(`スクラブ中`);
} else {
console.log(`スクラブ終了`);
}
};
new Rola("[data-rola-trigger]", { scrub: true }, callback);

これにより、CSSだけでは表現できないようなこともJavaScriptを使って実現できるようになります。

例えば、スクロール値や進行度を画面に表示したり、GSPAのようなアニメーションライブラリを使ってアニメーションを作成したりすることができます。