デモ
デモを読み込めませんでした。
仕様
- 用途
- ローディング
- 動作
- DOM
- 種類
- レシピ
- 動作確認
- three 0.186.0・gsap 3.15.0
- 公開日
しくみと調整
3 つの点を横に並べ、左から順に 1 つずつ跳ね上げて戻します。跳ねているあいだだけ点の色が変わるので、小さな点でもどこが動いているかを読み取れます。3 つが跳ね終わったら少し間を置いて、また左から繰り返します。
上りは 0.3 秒の power2.out で、隣の点とは 0.12 秒ずらします。上りを減速にすると、往復の折り返しで下りが加速に変わり、落ちて着地したように見えます。跳ねる高さは点の直径の 1.3 倍、次の周までの間は 0.46 秒です。この間を詰めると、待っている人を急かす速さになります。
往復の指定(yoyo と repeat)は、必ず stagger の中に書きます。外に書くと、3 つがまとめて上がってまとめて下りる 1 つの動きになり、順に跳ねる形がそのまま消えます。
読み込みが終わったときに抜ける口を、最初に作っておきます。終わりを知らせる関数を 1 つ用意し、その中で繰り返しを止めて要素を取り除けば、読み込みが済んだのに点だけ回り続けることがありません。画面には出さない「読み込み中」の一文を添えておくと、読み上げにも待っていることが伝わります。
点の数を増やしても、ずらす間隔を変えるだけで同じ形を保てます。終わりの見当が付かない待ち時間に向いていて、送信の待ち、一覧の読み込み、ページの切り替えなどに使えます。受け取った量が数で分かるものは、進み具合を出す表示のほうが待ちやすくなります。
コード
<div class="dots-loader" role="status">
<span class="dots-loader__dot"></span>
<span class="dots-loader__dot"></span>
<span class="dots-loader__dot"></span>
<span class="dots-loader__text">読み込み中</span>
</div>
.dots-loader {
--dot: 14px; /* 点の直径 */
--gap: 10px; /* 点の間 */
--ink: #262626; /* 休んでいる点の色 */
--jump: #ff5a1f; /* 跳ねているあいだの点の色 */
--ground: #f2f1ed; /* 地の色 */
position: fixed;
inset: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
gap: var(--gap);
background: var(--ground);
}
.dots-loader__dot {
width: var(--dot);
height: var(--dot);
border-radius: 50%;
background: var(--ink);
}
/* 読み上げにだけ届く文言。画面には出さない */
.dots-loader__text {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
import { gsap } from "gsap";
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
function createLoader(root) {
const dots = root.querySelectorAll(".dots-loader__dot");
// 色と大きさは CSS が正。GSAP は var(--name) のままでは補間できないので、値にして渡す
const jump = getComputedStyle(root).getPropertyValue("--jump").trim();
const lift = dots[0].offsetHeight * 1.3;
// yoyo と repeat は stagger の中に書く(外に書くと、3 つがまとめて往復する)。
// repeatDelay は、跳ね終わってから次の周が始まるまでの間
const bounce = gsap.timeline({ repeat: -1, repeatDelay: 0.46 }).to(dots, {
y: reduceMotion ? 0 : -lift, // 動きを減らす設定では、色の変化だけで順番を見せる
backgroundColor: jump,
duration: 0.3,
ease: "power2.out",
stagger: { each: 0.12, yoyo: true, repeat: 1 },
});
return {
// 読み込みが終わったら呼ぶ。呼ぶまで跳ね続ける
done() {
gsap.to(root, {
autoAlpha: 0,
duration: reduceMotion ? 0 : 0.3,
onComplete: () => {
bounce.kill();
root.remove();
},
});
},
};
}
// 例: fetch や画像の読み込みを待って loader.done()
export const loader = createLoader(document.querySelector(".dots-loader"));