無限ループローダー
SVGの∞パス上をグラデーションの発光線がstroke-dashで滑らかに周回するローダー。ブランド感のある待機演出として印象的に使えます。
ライブデモ
使用例(お題: SaaS FlowDesk)
この技法を「SaaS FlowDesk」というテーマのダミーサイトで実際に使った例です。
HTML
<!-- FlowDesk:ワークスペース準備中スプラッシュ。∞ローダーが周回→本編CTAへ -->
<div class="fd-stage" id="fdStage">
<!-- 本編(背面に常駐) -->
<main class="fd-ready">
<span class="fd-ready__logo"><span class="fd-ready__mark">◆</span> FlowDesk</span>
<h1 class="fd-ready__title">ワークスペースの<br>準備ができました。</h1>
<p class="fd-ready__lead">チームのタスクとダッシュボードを同期しました。</p>
<a class="fd-ready__btn" href="#">ダッシュボードを開く</a>
</main>
<!-- ローディングオーバーレイ -->
<div class="fd-load" id="fdLoad">
<!-- ∞パスを発光線が周回する -->
<svg class="fd-inf" viewBox="0 0 200 100" aria-label="読み込み中">
<defs>
<linearGradient id="fdGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0" stop-color="#4f7cff" stop-opacity="0"/>
<stop offset="0.5" stop-color="#8fb0ff"/>
<stop offset="1" stop-color="#4f7cff" stop-opacity="0"/>
</linearGradient>
</defs>
<path class="fd-inf__bg"
d="M40,50 C40,25 70,25 100,50 C130,75 160,75 160,50 C160,25 130,25 100,50 C70,75 40,75 40,50 Z"/>
<path class="fd-inf__line"
d="M40,50 C40,25 70,25 100,50 C130,75 160,75 160,50 C160,25 130,25 100,50 C70,75 40,75 40,50 Z"/>
</svg>
<p class="fd-load__name"><span class="fd-load__mark">◆</span> FlowDesk</p>
<p class="fd-load__sub">ワークスペースを準備しています…</p>
</div>
</div>
CSS
/* FlowDesk:∞ ローダー → 本編CTA */
:root {
--navy: #0f1b34;
--navy2: #16264a;
--blue: #4f7cff;
--muted: #9fb0d4;
}
* { box-sizing: border-box; }
body {
margin: 0;
height: 400px;
font-family: "Segoe UI", "Hiragino Kaku Gothic ProN", system-ui, sans-serif;
overflow: hidden;
}
.fd-stage { position: relative; height: 400px; background: var(--navy); }
/* 本編 */
.fd-ready {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
justify-content: center;
padding: 0 36px;
color: #fff;
background:
radial-gradient(700px 300px at 80% -10%, rgba(79,124,255,0.28), transparent 60%),
var(--navy);
}
.fd-ready__logo { font-size: 14px; font-weight: 700; color: var(--muted); margin-bottom: 14px; }
.fd-ready__mark { color: var(--blue); }
.fd-ready__title { margin: 0 0 12px; font-size: 28px; line-height: 1.4; font-weight: 700; }
.fd-ready__lead { margin: 0 0 22px; font-size: 13px; color: var(--muted); line-height: 1.7; }
.fd-ready__btn {
align-self: flex-start;
padding: 12px 24px;
border-radius: 10px;
background: var(--blue);
color: #fff;
font-size: 13px;
font-weight: 700;
text-decoration: none;
box-shadow: 0 10px 26px rgba(79,124,255,0.45);
}
/* ローディングオーバーレイ */
.fd-load {
position: absolute;
inset: 0;
z-index: 5;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: var(--navy);
transition: opacity 0.6s ease, visibility 0.6s ease;
}
.fd-load.is-done { opacity: 0; visibility: hidden; }
/* ∞ SVG */
.fd-inf { width: 200px; height: 100px; }
.fd-inf__bg {
fill: none;
stroke: rgba(255,255,255,0.08);
stroke-width: 5;
}
.fd-inf__line {
fill: none;
stroke: url(#fdGrad);
stroke-width: 5;
stroke-linecap: round;
/* 発光線がパス上を滑らかに周回 */
stroke-dasharray: 90 360;
filter: drop-shadow(0 0 6px rgba(79,124,255,0.8));
animation: fd-orbit 2s linear infinite;
}
@keyframes fd-orbit { to { stroke-dashoffset: -450; } }
.fd-load__name {
margin: 10px 0 0;
font-size: 16px;
font-weight: 700;
letter-spacing: 0.04em;
color: #fff;
}
.fd-load__mark { color: var(--blue); }
.fd-load__sub { margin: 6px 0 0; font-size: 11px; color: var(--muted); letter-spacing: 0.06em; }
@media (prefers-reduced-motion: reduce) {
.fd-inf__line { animation: none; }
.fd-load { transition: none; }
}
JavaScript
// FlowDesk:∞ ローダーをしばらく見せてから本編へ(疑似準備・ループ)
const load = document.getElementById('fdLoad');
function run() {
if (!load) return;
load.classList.remove('is-done');
// 2.4秒準備 → オーバーレイをフェードアウトして本編表示
setTimeout(() => load.classList.add('is-done'), 2400);
// 完了から少し置いて再ループ
setTimeout(run, 5200);
}
// 初回起動
run();
コード
HTML
<!-- 無限ループローダー: SVGの∞パス上を光のドットが滑らかに周回する -->
<div class="if-stage">
<div class="if-box">
<svg class="if-svg" viewBox="0 0 200 100" aria-hidden="true">
<defs>
<linearGradient id="ifGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="50%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#f472b6"/>
</linearGradient>
</defs>
<!-- ∞ の軌道(薄いガイド) -->
<path class="if-track"
d="M100,50 C100,20 60,20 50,50 C40,80 0,80 0,50 C0,20 40,20 50,50 C60,80 100,80 100,50 C100,20 140,20 150,50 C160,80 200,80 200,50 C200,20 160,20 150,50 C140,80 100,80 100,50 Z"/>
<!-- なぞって描く発光線(同じパスを直接描画) -->
<path class="if-glow"
d="M100,50 C100,20 60,20 50,50 C40,80 0,80 0,50 C0,20 40,20 50,50 C60,80 100,80 100,50 C100,20 140,20 150,50 C160,80 200,80 200,50 C200,20 160,20 150,50 C140,80 100,80 100,50 Z"/>
</svg>
<p class="if-label">Loading<span class="if-ell">…</span></p>
</div>
</div>
CSS
:root {
--bg: #0b0f1e;
--track: rgba(255, 255, 255, .07);
--txt: #cdd6ff;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background:
radial-gradient(800px 500px at 50% 50%, #161d3d 0%, transparent 60%),
var(--bg);
color: var(--txt);
}
.if-box {
display: grid;
justify-items: center;
gap: 18px;
padding: 24px;
}
.if-svg { width: 240px; height: 120px; overflow: visible; }
.if-track {
fill: none;
stroke: var(--track);
stroke-width: 4;
}
/* 発光線: dash を流して∞をなぞる動き */
.if-glow {
fill: none;
stroke: url(#ifGrad);
stroke-width: 4;
stroke-linecap: round;
/* パス長 ≒ 590。dash+gap を 1周期=590 に合わせ、
offset を 1周分(-590)動かして継ぎ目なくループさせる */
stroke-dasharray: 110 480;
filter: drop-shadow(0 0 5px rgba(167, 139, 250, .8));
animation: if-run 2.6s linear infinite;
}
@keyframes if-run {
to { stroke-dashoffset: -590; }
}
.if-label {
margin: 0;
font-size: 13px;
letter-spacing: .28em;
text-transform: uppercase;
color: rgba(205, 214, 255, .65);
}
/* 末尾の点が順に現れる */
.if-ell { display: inline-block; width: 1.4em; text-align: left; animation: if-dots 1.4s steps(4) infinite; }
@keyframes if-dots {
0% { clip-path: inset(0 100% 0 0); }
100% { clip-path: inset(0 0 0 0); }
}
@media (prefers-reduced-motion: reduce) {
.if-glow { animation-duration: 8s; }
.if-ell { animation: none; }
}
JavaScript
// このデモは SVG パスと CSS アニメーションのみで動作するため JS は不要
🤖 AIエージェント用プロンプト
このままコピーしてAIに貼り付け「追加する場所」だけ書き換えればOK
あなたは熟練のフロントエンドエンジニアです。私のWebサイトに「無限ループローダー」の効果を追加してください。
# 追加してほしい効果
無限ループローダー(ローダー & スケルトン)
SVGの∞パス上をグラデーションの発光線がstroke-dashで滑らかに周回するローダー。ブランド感のある待機演出として印象的に使えます。
# 追加する場所
👉【ここに対象箇所を記入:例「トップのヒーローセクション」「お問い合わせボタン」「記事カードの一覧」など】
# 参考実装(この見た目・挙動を再現してください)
【HTML】
<!-- 無限ループローダー: SVGの∞パス上を光のドットが滑らかに周回する -->
<div class="if-stage">
<div class="if-box">
<svg class="if-svg" viewBox="0 0 200 100" aria-hidden="true">
<defs>
<linearGradient id="ifGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#22d3ee"/>
<stop offset="50%" stop-color="#a78bfa"/>
<stop offset="100%" stop-color="#f472b6"/>
</linearGradient>
</defs>
<!-- ∞ の軌道(薄いガイド) -->
<path class="if-track"
d="M100,50 C100,20 60,20 50,50 C40,80 0,80 0,50 C0,20 40,20 50,50 C60,80 100,80 100,50 C100,20 140,20 150,50 C160,80 200,80 200,50 C200,20 160,20 150,50 C140,80 100,80 100,50 Z"/>
<!-- なぞって描く発光線(同じパスを直接描画) -->
<path class="if-glow"
d="M100,50 C100,20 60,20 50,50 C40,80 0,80 0,50 C0,20 40,20 50,50 C60,80 100,80 100,50 C100,20 140,20 150,50 C160,80 200,80 200,50 C200,20 160,20 150,50 C140,80 100,80 100,50 Z"/>
</svg>
<p class="if-label">Loading<span class="if-ell">…</span></p>
</div>
</div>
【CSS】
:root {
--bg: #0b0f1e;
--track: rgba(255, 255, 255, .07);
--txt: #cdd6ff;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
font-family: "Segoe UI", system-ui, sans-serif;
background:
radial-gradient(800px 500px at 50% 50%, #161d3d 0%, transparent 60%),
var(--bg);
color: var(--txt);
}
.if-box {
display: grid;
justify-items: center;
gap: 18px;
padding: 24px;
}
.if-svg { width: 240px; height: 120px; overflow: visible; }
.if-track {
fill: none;
stroke: var(--track);
stroke-width: 4;
}
/* 発光線: dash を流して∞をなぞる動き */
.if-glow {
fill: none;
stroke: url(#ifGrad);
stroke-width: 4;
stroke-linecap: round;
/* パス長 ≒ 590。dash+gap を 1周期=590 に合わせ、
offset を 1周分(-590)動かして継ぎ目なくループさせる */
stroke-dasharray: 110 480;
filter: drop-shadow(0 0 5px rgba(167, 139, 250, .8));
animation: if-run 2.6s linear infinite;
}
@keyframes if-run {
to { stroke-dashoffset: -590; }
}
.if-label {
margin: 0;
font-size: 13px;
letter-spacing: .28em;
text-transform: uppercase;
color: rgba(205, 214, 255, .65);
}
/* 末尾の点が順に現れる */
.if-ell { display: inline-block; width: 1.4em; text-align: left; animation: if-dots 1.4s steps(4) infinite; }
@keyframes if-dots {
0% { clip-path: inset(0 100% 0 0); }
100% { clip-path: inset(0 0 0 0); }
}
@media (prefers-reduced-motion: reduce) {
.if-glow { animation-duration: 8s; }
.if-ell { animation: none; }
}
【JavaScript】
// このデモは SVG パスと CSS アニメーションのみで動作するため JS は不要
# 外部ライブラリ
なし(追加ライブラリ不要)
# 守ってほしいこと
- 既存のHTML構造・レイアウト・デザインを壊さないこと。必要に応じてクラス名・色・サイズを私のサイトに合わせて調整してよい。
- クラス名やidが既存と衝突しないよう、必要なら接頭辞で名前空間を分けること。
- レスポンシブ対応と prefers-reduced-motion への配慮を入れること。
- 私のサイトのフレームワーク(React / Vue / 素のHTML など)に合わせて実装すること。不明な場合は素のHTML/CSS/JSで提示し、組み込み手順も説明すること。
- 変更後の確認手順も簡潔に教えてください。