【Gsap】
SVGテキストアニメーション
このコードは、GSAPのScrollTriggerを使用して、スクロールイベントに基づいてSVGテキストの色を動的に変更するアニメーションを設定しています。ユーザーがページをスクロールすると、SVGテキストと黄色のボックスの位置とサイズを取得し、SVGテキストの下端が黄色のボックスの上端に重なるかどうかを確認します。テキストがボックスに重なる場合にはテキストの色を黒に、重ならない場合には白に変更することで、背景に対してテキストが読みやすい色で表示されるようにしています。この動的な色の変更により、スクロールに応じた視覚効果を提供し、ユーザー体験を向上させています。
目次
実装内容
パターン1
スクロールとテキストを紐づけて表示し画面を固定
パターン2
startの位置でアニメーションを一回のみ実装
パターン3
パターン1の応用SVGテキストを徐々に白色に変化させる
コード
全体のコード
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.pin-wrap {
position: relative;
/* 子要素の位置を相対的に配置 */
margin-bottom: 100px;
}
.top-img {
background-image: url(https://picsum.photos/1000/500?random=3);
/* ランダムな画像を背景画像として設定 */
background-repeat: no-repeat;
/* 背景画像の繰り返しを無効化 */
background-size: cover;
/* 背景画像を要素の大きさに合わせてカバー */
background-position: center;
/* 背景画像を中央に配置 */
width: 100%;
/* 幅を100%に設定 */
height: 50vh;
/* 高さをビューポートの50%に設定 */
}
svg {
font-size: clamp(10px, 1.8vw, 16px);
position: absolute;
/* 絶対位置に配置 */
left: 50%;
/* 左端から50%の位置に配置 */
top: 30%;
/* 上端から30%の位置に配置 */
transform: translate(-50%, -50%);
/* 中央に揃えるために位置を調整 */
}
text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.yellow-box {
background-color: yellow;
/* 背景色を黄色に設定 */
width: 100%;
/* 幅を100%に設定 */
height: 50vh;
/* 高さをビューポートの50%に設定 */
}
.txt-black {
clip-path: inset(0px 0px 0px 0px);
transition: clip-path 0.3s;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.2/gsap.min.js"></script>
<!-- GSAPのメインライブラリを読み込み -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.2/ScrollTrigger.min.js"></script>
<!-- GSAPのScrollTriggerプラグインを読み込み -->
</head>
<body>
<h1>スクロールとテキストを紐づけて表示し<br>画面を固定</h1>
<div class="pin-wrap js-cont-01">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="3em"
font-weight="700" fill="#fff" class="svg-text">
<!-- SVGテキストを中央に配置し、スタイルを設定 -->
これはSVGテキスト01です
</text>
</svg>
<div class="top-img"></div><!-- 背景画像を表示する要素 -->
<div class="yellow-box"></div><!-- 黄色のボックス -->
</div><!-- ラップ要素の終了 -->
<h1>startの位置でアニメーションを一回のみ実装</h1>
<div class="pin-wrap js-cont-02">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" font-family="Arial" font-size="3em"
font-weight="700" fill="#fff" class="svg-text">
<!-- SVGテキストを中央に配置し、スタイルを設定 -->
これはSVGテキスト02です
</text>
</svg>
<div class="top-img"></div><!-- 背景画像を表示する要素 -->
<div class="yellow-box"></div><!-- 黄色のボックス -->
</div><!-- ラップ要素の終了 -->
<div class="pin-wrap js-cont-03">
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<g class="svg-text">
<text x="50%" y="50%" class="txt-white" dominant-baseline="middle" text-anchor="middle" font-family="Arial"
font-size="3em" font-weight="700" fill="white">
これはSVGテキスト03です
</text>
<text x="50%" y="50%" class="txt-black" dominant-baseline="middle" text-anchor="middle" font-family="Arial"
font-size="3em" font-weight="700" fill="black">
これはSVGテキスト03です
</text>
</g>
</svg>
<div class="top-img"></div>
<div class="yellow-box"></div>
</div>
<script>
gsap.registerPlugin(ScrollTrigger);
const text01 = document.querySelector('.js-cont-01 .svg-text');
gsap.to(text01, {
y: "400px",
ease: "none",
scrollTrigger: {
trigger: ".js-cont-01",
start: "top top",
end: "80% 50%",
scrub: true,
pin: true,
markers: true,
onUpdate: () => {
const textRect = text01.getBoundingClientRect();
const box01 = document.querySelector('.js-cont-01 .yellow-box');
const boxRect = box01.getBoundingClientRect();
if (textRect.bottom > boxRect.top) {
text01.setAttribute('fill', 'black');
} else {
text01.setAttribute('fill', '#fff');
}
}
}
});
const text02 = document.querySelector('.js-cont-02 .svg-text');
const box02 = document.querySelector('.js-cont-02 .yellow-box');
// タイムラインを作成し、ScrollTriggerを設定
const tl = gsap.timeline({
scrollTrigger: {
trigger: ".js-cont-02", // トリガー要素を指定
start: "50% 50%", // アニメーションの開始位置を指定
markers: true, // デバッグ用マーカーを表示
}
});
// Y軸方向のアニメーションと色変更をチェイン
tl.to(text02, {
y: "400px", ease: "none", onUpdate: function () {
// テキストとボックスの位置を取得
const textRect = text02.getBoundingClientRect();
const boxRect = box02.getBoundingClientRect();
// テキストの下部がボックスの上部に達した場合に色を黒に変更
if (textRect.bottom >= boxRect.top) {
text02.setAttribute('fill', 'black');
}
}
});
const text03 = document.querySelector('.js-cont-03 .svg-text');
const blackText = document.querySelector('.txt-black');
const yellowBox = document.querySelector('.js-cont-03 .yellow-box');
gsap.to(text03, {
y: "300px",
ease: "none",
scrollTrigger: {
trigger: ".js-cont-03",
start: "top top",
scrub: true,
pin: true,
markers: true,
onUpdate: () => {
const textRect = text03.getBoundingClientRect();
const yellowBoxTop = yellowBox.getBoundingClientRect().top;
let clipValue = 0;
if (yellowBoxTop < textRect.bottom) {
clipValue = textRect.bottom - yellowBoxTop;
}
blackText.style.clipPath = `inset(0px 0px ${clipValue}px 0px)`;
}
}
});
</script>
</body>
</html>
ポイント解説
GSAPのpin
オプションについて
GSAPのpin
オプションは、特定の要素をスクロール位置に固定するために使用されます。例えば、要素がビューポート内に入った時にその位置で固定され、他の要素がスクロールしていく間もその位置に留まるようになります。これにより、ユーザーがスクロールする際に特定のコンテンツを強調表示することができます。
ScrollTriggerのscrub
オプションについて
scrub
オプションは、スクロールの進行に応じてアニメーションをスムーズに同期させるために使用されます。scrub: true
と設定すると、ユーザーがスクロールする速度と位置に基づいてアニメーションが連動します。これにより、スクロールとアニメーションの動きが自然にリンクします。
clip-path: inset(0px 0px 0px 0px);
の解説
clip-path
プロパティは、要素の表示領域を制御するために使用されます。inset
は、要素の内側からのオフセットを指定します。例えば、inset(0px 0px 0px 0px)
は、要素の全領域を表示することを意味します。この値はアニメーションによって動的に変更され、要素の表示領域が部分的に制御されます。例えば、スクロールに応じて特定の部分だけが表示されたり隠れたりする効果を実現できます。
Gsap onUpdateプロパティ
onUpdate: () => {
// text01要素の現在の位置とサイズを取得
const textRect = text01.getBoundingClientRect();
// js-cont-01クラスを持つ要素内のyellow-box要素を取得
const box01 = document.querySelector('.js-cont-01 .yellow-box');
// box01要素の現在の位置とサイズを取得
const boxRect = box01.getBoundingClientRect();
// text01の下端がbox01の上端を超えた場合
if (textRect.bottom > boxRect.top) {
// text01のfill属性を黒に設定
text01.setAttribute('fill', 'black');
} else {
// text01のfill属性を白に設定
text01.setAttribute('fill', '#fff');
}
}
詳細解説
textRect
の取得:text01.getBoundingClientRect()
を使用して、text01
要素(スクロールに応じてアニメーションしているSVGテキスト)の位置とサイズを取得します。textRect
は、この要素の位置(上端、下端、左端、右端など)に関する情報を持つオブジェクトです。
box01
の取得:document.querySelector('.js-cont-01 .yellow-box')
を使用して、.js-cont-01
クラスを持つ要素内の.yellow-box
クラスを持つ要素を取得します。この要素は、黄色のボックスです。
boxRect
の取得:box01.getBoundingClientRect()
を使用して、box01
要素の位置とサイズを取得します。boxRect
は、この要素の位置に関する情報を持つオブジェクトです。
- 条件分岐:
if (textRect.bottom > boxRect.top)
は、text01
要素の下端がbox01
要素の上端を超えたかどうかをチェックします。- 超えた場合(つまり、
text01
がbox01
の上に重なる場合)、text01
のテキストの色を黒(fill='black'
)に設定します。 - そうでない場合(
text01
がbox01
の上に重ならない場合)、text01
のテキストの色を白(fill='#fff'
)に設定します。
このコードの目的は、スクロールに応じてSVGテキストの色を動的に変更することです。具体的には、テキストが黄色のボックスの上に重なると黒に、重ならないと白に変わるようにしています。これにより、背景に対してテキストが読みやすくなるような視覚効果を実現しています。
まとめ
- GsapでSVG画像に対してアニメーションを実施できる
- これらを組み合わせると、魅力的なWebサイトが構築できる
- Gsapはpin属性とscrubオプションを理解することが重要
- さらにCSSを組み合わせることで、より差別化が可能