画像読み込みに時間がかかっている表現
Webページをスクロールして画像が表示する際には、CSSアニメーションを使用して以下のいずれかのアニメーションで表示されることが一般的です。
- 非表示から表示
- 画面外から表示
- 拡大して表示
- ぼかして表示
- 光って表示
- etc.
色々な方法があるのですが、下の画像のように読み込みに時間がかかっているようなCSSアニメーションの表現が見当たらなかったので、clip-pathを使用して作成してみました。
※ 上の画像の例だとアニメーションが繰り返し確認できるよう、アニメーションプロパティに「infinite」を指定していますが、これから作成するのは「forwards」を指定した1回だけのアニメーションです。
clip-pathとは
clip-pathはCSSで要素の表示領域を切り抜くためのプロパティです。
このプロパティを使用することで、要素を指定した形状に切り抜くことができます。
例えば以下のように要素に「clip-path: inset(0 0 50% 0);」を指定すれば、上から50%の位置までを切り抜いて表示できます。
.clip-half {
clip-path: inset(0 0 50% 0);
}
clip-pathでCSSアニメーション
clip-pathは指定した範囲を切り抜けるので、これを使えば画像読み込みに時間がかかっているようなCSSアニメーションを作成できます。
まず切り抜く要素に「opacity: 0」を指定して非表示にするコードを作成します。
そしてスクロールして表示された要素に追加する「.lazy-load-anime」に「opacity: 1」と「clip-path: inset(0 0 100% 0)」を指定して、animationプロパティで「clip-path: inset(0 0 0 0);」まで10分割したアニメーションを作成します。
「clip-path: inset(0 0 100% 0)」で非表示になるのだから、opacityは使わなくて良いのでは?…と疑問に思われる方もいるかと思います。
実はこのあとに説明するJavaScriptのIntersectionObserverは「clip-path: inset(0 0 100% 0)」で切りの抜いた状態だと交差を検知できないため、このようなコードになっています。
animationの「4s」は「再生時間4秒」です。forwardsがないとアニメーション終了後に最初の状態に戻ってしまうので、必ず追加してください。
.lazy-load-anime-hide {
opacity: 0;
}
.lazy-load-anime {
opacity: 1;
clip-path: inset(0 0 100% 0);
animation: lazy-load-anime 4s steps(10) forwards;
}
@keyframes lazy-load-anime {
to {
clip-path: inset(0 0 0 0);
}
}
あとはJavaScriptのIntersectionObserverでスクロールして「.lazy-load-anime-hide」に近づいたら「.lazy-load-anime」を追加するコードを作成すれば完成です。
const options = {
root: null,
rootMargin: '0px',
threshold: 0.5,
}
const observerCallback = (entries, observer) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('lazy-load-anime')
observer.unobserve(entry.target)
}
})
}
const observer = new IntersectionObserver(observerCallback, options)
const targetElements = document.querySelectorAll('.lazy-load-anime-hide')
if (targetElements) {
targetElements.forEach((element) => {
observer.observe(element)
})
}
clip path inset animation sample
stepを使わずinset(100%)からinset(0)にするとスムーズに四角形が広がって表示されるアニメーションになります。
.lazy-load-anime {
opacity: 1;
clip-path: inset(100%);
animation: lazy-load-anime 2s forwards;
}
@keyframes lazy-load-anime {
to {
clip-path: inset(0);
}
}
clip path inset smooth animation sample
円形の場合はcircleを使います。
circleの場合は開始は0で終了は100%になります。
.lazy-load-anime {
opacity: 1;
clip-path: circle(0);
animation: lazy-load-anime 2s forwards;
}
@keyframes lazy-load-anime {
to {
clip-path: circle(100%);
}
}
clip path circle animation sample
さらにclip-path: polygon()を使えば多角形の切り抜きができるので、次のような中心点(50% 50%)から星型に変形する複雑なCSSアニメーションなども作成できます。
.lazy-load-anime {
opacity: 1;
clip-path: polygon(
50% 50%,
50% 50%,
50% 50%,
50% 50%,
50% 50%,
50% 50%,
50% 50%,
50% 50%,
50% 50%,
50% 50%
);
animation: lazy-load-anime 2s forwards;
}
@keyframes lazy-load-anime {
to {
clip-path: polygon(
50% 0%,
61% 35%,
98% 35%,
68% 57%,
79% 91%,
50% 70%,
21% 91%,
32% 57%,
2% 35%,
39% 35%
);
}
}
clip path polygon animation sample