Liquid Bubble Loader リキッドバブルローダー
Translucent capsule with organic rising and popping liquid bubbles. 微細な気泡の浮上と弾けるアニメーションによる親しみやすい液体ローダー。
ライブデモ Live Demo
抽出中... Filtering...
概要・用途・特徴Overview, Usage & Features
何ができるかWhat it does
An organic loader depicting rising liquid bubbles inside a rounded translucent capsule container.
丸みを帯びた半透明カプセルの中で、微小な気泡が湧き上がって頂部で弾ける液体風ローダーです。
どこで使うかWhere to use
Great for search filter processing, chemistry/science dashboards, consumer brand apps, and clean loading screens.
検索フィルターの絞り込み処理、サイエンス・バイオ系UI、リフレッシュ待機画面などに最適です。
特徴Key features
Staggered keyframe emergence, radial specular highlight gradients, role="status" accessibility, prefers-reduced-motion fallback.
時差をつけたバブルの上昇アニメーション、ハイライト光沢グラデーション、role="status"対応、prefers-reduced-motion対応。
調整可能パラメータ Adjustable Parameters
| Parameter | Default | Description |
|---|---|---|
width | 52px | Width of the capsule container |
speed | 2.2s | Duration of one full bubble rise cycle |
color | #38bdf8 | Primary bubble glow color |
実装コード Implementation Code
<div class="s020-loader" role="status" aria-label="Loading">
<span class="s020-sr-only">Loading</span>
<div class="s020-capsule" aria-hidden="true">
<div class="s020-bubble"></div>
<div class="s020-bubble"></div>
<div class="s020-bubble"></div>
<div class="s020-bubble"></div>
</div>
</div>
.s020-loader {
--s020-width: 52px;
--s020-height: 72px;
--s020-speed: 2.2s;
--s020-bubble-color: #38bdf8;
position: relative;
width: var(--s020-width);
height: var(--s020-height);
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.s020-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.s020-capsule {
position: absolute;
inset: 0;
border-radius: 26px;
border: 2px solid rgba(148, 163, 184, 0.25);
background: rgba(15, 23, 42, 0.4);
box-shadow: inset 0 0 12px rgba(56, 189, 248, 0.1);
overflow: hidden;
}
.s020-bubble {
position: absolute;
bottom: 6px;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, #ffffff, var(--s020-bubble-color));
box-shadow: 0 0 8px var(--s020-bubble-color);
animation: s020-rise var(--s020-speed) cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.s020-bubble:nth-child(1) { left: 28%; width: 14px; height: 14px; animation-delay: 0s; }
.s020-bubble:nth-child(2) { left: 52%; width: 10px; height: 10px; animation-delay: calc(var(--s020-speed) * -0.33); }
.s020-bubble:nth-child(3) { left: 36%; width: 8px; height: 8px; animation-delay: calc(var(--s020-speed) * -0.66); }
.s020-bubble:nth-child(4) { left: 18%; width: 12px; height: 12px; animation-delay: calc(var(--s020-speed) * -0.85); }
@keyframes s020-rise {
0% { transform: translateY(0) scale(0.3); opacity: 0; }
15% { opacity: 0.9; transform: translateY(-8px) scale(1); }
50% { transform: translateY(-32px) translateX(3px) scale(1.05); }
85% { opacity: 0.85; transform: translateY(-52px) translateX(-2px) scale(0.95); }
100% { opacity: 0; transform: translateY(-60px) scale(1.35); }
}
.s020-loader.paused,
.s020-loader[data-paused="true"],
.s020-loader.paused .s020-bubble,
.s020-loader[data-paused="true"] .s020-bubble {
animation-play-state: paused !important;
}
@media screen and (prefers-reduced-motion: reduce) {
.s020-bubble {
animation: none !important;
opacity: 0.6;
transform: translateY(-24px);
}
}
import React from 'react';
import './S-020.css';
export default function LiquidBubbleLoader({
width = 52,
height = 72,
speed = 2.2,
color = '#38bdf8',
paused = false
}) {
const style = {
'--s020-width': `${width}px`,
'--s020-height': `${height}px`,
'--s020-speed': `${speed}s`,
'--s020-bubble-color': color,
};
return (
<div
className={`s020-loader ${paused ? 'paused' : ''}`}
style={style}
role="status"
aria-label="Loading"
>
<span className="s020-sr-only">Loading</span>
<div className="s020-capsule" aria-hidden="true">
<div className="s020-bubble" />
<div className="s020-bubble" />
<div className="s020-bubble" />
<div className="s020-bubble" />
</div>
</div>
);
}
.s020-loader {
width: var(--s020-width, 52px);
height: var(--s020-height, 72px);
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
}
.s020-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.s020-capsule {
position: absolute;
inset: 0;
border-radius: 26px;
border: 2px solid rgba(148, 163, 184, 0.25);
background: rgba(15, 23, 42, 0.4);
box-shadow: inset 0 0 12px rgba(56, 189, 248, 0.1);
overflow: hidden;
}
.s020-bubble {
position: absolute;
bottom: 6px;
border-radius: 50%;
background: radial-gradient(circle at 30% 30%, #ffffff, var(--s020-bubble-color, #38bdf8));
box-shadow: 0 0 8px var(--s020-bubble-color, #38bdf8);
animation: s020-rise var(--s020-speed, 2.2s) cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.s020-bubble:nth-child(1) { left: 28%; width: 14px; height: 14px; animation-delay: 0s; }
.s020-bubble:nth-child(2) { left: 52%; width: 10px; height: 10px; animation-delay: calc(var(--s020-speed, 2.2s) * -0.33); }
.s020-bubble:nth-child(3) { left: 36%; width: 8px; height: 8px; animation-delay: calc(var(--s020-speed, 2.2s) * -0.66); }
.s020-bubble:nth-child(4) { left: 18%; width: 12px; height: 12px; animation-delay: calc(var(--s020-speed, 2.2s) * -0.85); }
@keyframes s020-rise {
0% { transform: translateY(0) scale(0.3); opacity: 0; }
15% { opacity: 0.9; transform: translateY(-8px) scale(1); }
50% { transform: translateY(-32px) translateX(3px) scale(1.05); }
85% { opacity: 0.85; transform: translateY(-52px) translateX(-2px) scale(0.95); }
100% { opacity: 0; transform: translateY(-60px) scale(1.35); }
}
.s020-loader.paused,
.s020-loader[data-paused="true"],
.s020-loader.paused .s020-bubble,
.s020-loader[data-paused="true"] .s020-bubble {
animation-play-state: paused !important;
}
@media screen and (prefers-reduced-motion: reduce) {
.s020-bubble {
animation: none !important;
opacity: 0.6;
transform: translateY(-24px);
}
}
仕組みとカスタマイズHow It Works & Customization
仕組みHow it works
Four individual bubble nodes are assigned varying horizontal offsets and negative animation delays, ascending with subtle horizontal drift.
4つのバブル要素に異なる水平位置と負の遅延を設定し、左右の揺らぎを伴う上昇キーフレームを適用しています。
カスタマイズ方法Customization
Tweak duration, bubble color, and capsule dimensions via CSS variables or React component props.
CSSカスタムプロパティ(--s020-width, --s020-height, --s020-speed, --s020-bubble-color)またはReact propsで自在に色や速度を変更できます。
注意点Caveats
Provide a meaningful text alternative in aria-label or surrounding DOM for assistive technology.
支援技術ユーザー向けに、aria-labelまたは周囲のテキストでローディング中であることを明示してください。
よくある質問 Frequently Asked Questions
How can I change the bubble ascent rate? バブルの上昇速度を変更するにはどうすればよいですか?
Modify the --s020-speed CSS custom property or pass the speed prop in React.
CSSカスタムプロパティ --s020-speed の値を変更するか、Reactの speed prop に秒数を指定してください。
Can the outer capsule boundary be hidden? 外側のカプセルの枠線を非表示にできますか?
Yes, set border: none and background: transparent on .s020-capsule for a borderless bubble stream.
はい、.s020-capsule の border を none に設定することで枠線なしのシームレスなバブル上昇にできます。
AIへの指示テンプレート AI Prompt Template
以下をAIに貼り付けると実装を依頼できます。 Paste the following into your AI assistant to request implementation.