
説明が難しいので、以下の動きをご確認ください。
スクロールすると写真の下からブラインドが徐々に出現します。
利用するライブラリ
今回のライブラリは3つです。
<script src="js/gsap.js"></script> <script src="js/ScrollTrigger.js"></script> <script src="js/lenis.js"></script>
アニメーション・スクロールイベント・慣性スクロールのメジャーなやつです。
基本の動作設定
まずは、FVのイメージにブラインドを設定します。
javascript
gsap.registerPlugin(ScrollTrigger);
window.addEventListener("DOMContentLoaded", () => {
const lenis = new Lenis({
smooth: true,
lerp: 0.1
});
function raf(time) {
lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => {
lenis.raf(time * 1000);
});
gsap.ticker.lagSmoothing(0);
const ROWS = 40;
const blind = document.querySelector(".sc-blind");
if (!blind) return;
for (let i = 0; i < ROWS; i++) {
const span = document.createElement("span");
blind.appendChild(span);
}
const blinds = blind.querySelectorAll("span");
gsap.to(blinds, {
scaleY: 1,
ease: Power0.easeNone,
stagger: {
each: 0.04,
from: "end"
},
scrollTrigger: {
trigger: ".sc-2",
start: "top bottom",
end: "top top",
scrub: true,
invalidateOnRefresh: true
}
});
ScrollTrigger.refresh();
});
css
.section {
position: relative;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.sc{
overflow: hidden;
color:#fff;
}
.sc:nth-child(even){
position: relative;
background: #fff;
color:#000;
}
.sc-blind{
position: absolute;
inset: 0 0 0 0;
display: grid;
grid-template-rows: repeat(40, 1fr);
z-index: 10;
pointer-events: none;
}
.sc-blind span{
background: #fff;
transform-origin: center;
transform: scaleY(0);
}
/************************/
.section>h1 {
font-size: clamp(6rem, 7vw, 16rem);
line-height: 1;
}
.section .image {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: -1;
}
html
<div class="section sc"> <img class="image" src="img/1.jpg" alt=""/> <h1>01</h1> <div class="sc-blind"></div> </div> <div class="section sc"> <h1>02</h1> </div>
sc-blindはブラインドアニメーションになります。
sectionの表示をトリガーにブラインドアニメーションが発火します。
複数コンテンツの動作設定
基本を踏まえて、複数のコンテンツにブラインドアニメーションをするには大まかに2通りあります。
- sc-blindを複数作成し、jsに全て記述する。
- section内にsc-blindがあれば自動的にブラインドアニメーションを発火させる。
1の場合、都度チューニングが必要なのでエラー発生の可能性もありちょっと面倒です。
なので2で今回作成したいと思います。
javascript
gsap.registerPlugin(ScrollTrigger);
window.addEventListener("DOMContentLoaded", () => {
const lenis = new Lenis({ smooth: true, lerp: 0.1 });
function raf(time) {
lenis.raf(time);
requestAnimationFrame(raf);
}
requestAnimationFrame(raf);
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => lenis.raf(time * 1000));
gsap.ticker.lagSmoothing(0);
const ROWS = 40;
const blinds = gsap.utils.toArray(".sc-blind");
blinds.forEach((blindEl) => {
const section = blindEl.closest(".section");
if (!section) return;
// 次のsectionをトリガーにする
const nextSection = section.nextElementSibling;
if (!nextSection || !nextSection.classList.contains("section")) return;
// span を生成(既にあれば作らない)
if (blindEl.children.length === 0) {
for (let i = 0; i < ROWS; i++) {
blindEl.appendChild(document.createElement("span"));
}
}
const spans = blindEl.querySelectorAll("span");
gsap.to(spans, {
scaleY: 1,
ease: Power0.easeNone,
stagger: { each: 0.04, from: "end" },
scrollTrigger: {
trigger: nextSection,
start: "top bottom",
end: "top top",
scrub: true,
invalidateOnRefresh: true
// markers: true,
}
});
});
ScrollTrigger.refresh();
});
すべてのsc-blindを対象にします
const blinds = gsap.utils.toArray(".sc-blind");
親セクション(sc-blindが乗っているsection)を取得します。
const section = blindEl.closest(".section");
次のセクションをトリガーにします。
const nextSection = section.nextElementSibling;
ここがポイントでnextElementSiblingをgsapのtriggerに設定します。
trigger: nextSection
これで自動的にsc-blindがあるコンテンツは全てブラインドアニメーションが適用されます。
まとめ
ブラインドの数は
css
grid-template-rows: repeat(40, 1fr);
js
const ROWS = 40;
で調整します。40の部分をより大きな数値にすれば細かなブラインドが生成されますが意図した動きになるかはわかりません。
また連続したコンテンツに適用する場合、違和感もあったりするので多少用途の制限はあるかもですが、知ってると幅は広がる便利なギミックです。