06満ちていく水の円
丸い枠の中に水が満ちていく。波打つ水面は大きな正方形を回転させて作り、上昇の高さだけをtranslateYで動かすので、静かな水面がずっと揺れる。
使いどころファイルアップロード進捗、アンケート回答のゲージ
translate: 0 -60pxrotateoverflow: hidden

<main class="stage">
<div class="lq-tube is-demo" aria-hidden="true">
<div class="lq-water"></div>
</div>
</main>@use "../../../../site/static/demo-tokens" as *;
// ── 변수 3개 ──────────────────────────────────────────
$duration: 2s;
$easing: $ease-spring;
$color: $subject-sky;
@include stage($stage-yellow);
// 실사용: 로딩 중에만 .is-loading
.lq-tube {
position: relative;
width: 150px;
height: 150px;
border: 4px solid $subject-ink;
border-radius: 50%;
overflow: hidden; // 원 밖의 물은 잘린다
}
.lq-water {
position: absolute;
top: 100%;
left: calc(50% - 55px);
width: 110px;
height: 110px;
border-radius: 36%;
background: $color;
}
.lq-tube.is-loading .lq-water,
.lq-tube.is-demo .lq-water {
// 두 동작의 조합: 사각형의 회전(물결 윗면) + translateY 상승
animation: lq-wave 2s linear infinite,
lq-rise $duration $easing infinite;
}
@keyframes lq-wave {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes lq-rise {
0% { translate: 0 0; }
50% { translate: 0 -60px; }
100% { translate: 0 0; }
}
@media (prefers-reduced-motion: reduce) {
.lq-tube.is-loading .lq-water,
.lq-tube.is-demo .lq-water {
animation: none !important;
translate: 0 -30px !important; // 절반쯤 찬 물에 수면이 기울어진 정지 모양
transform: rotate(12deg) !important;
}
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #ffd23f;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.lq-tube {
position: relative;
width: 150px;
height: 150px;
border: 4px solid #17141a;
border-radius: 50%;
overflow: hidden;
}
.lq-water {
position: absolute;
top: 100%;
left: calc(50% - 55px);
width: 110px;
height: 110px;
border-radius: 36%;
background: #6ec8ff;
}
.lq-tube.is-loading .lq-water,
.lq-tube.is-demo .lq-water {
animation: lq-wave 2s linear infinite, lq-rise 2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
}
@keyframes lq-wave {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes lq-rise {
0% {
translate: 0 0;
}
50% {
translate: 0 -60px;
}
100% {
translate: 0 0;
}
}
@media (prefers-reduced-motion: reduce) {
.lq-tube.is-loading .lq-water,
.lq-tube.is-demo .lq-water {
animation: none !important;
translate: 0 -30px !important;
transform: rotate(12deg) !important;
}
}import { CSSProperties } from "react";
import styles from "./LiquidFill.module.scss";
type Vars = CSSProperties & {
"--duration"?: string;
"--easing"?: string;
"--color"?: string;
};
export interface LiquidFillProps {
duration?: string;
easing?: string;
color?: string;
/** 원 테두리 색 */
frameColor?: string;
}
export default function LiquidFill({
duration = "2s",
easing = "cubic-bezier(.2, .8, .2, 1)",
color = "#6ec8ff",
frameColor = "#17141a",
}: LiquidFillProps) {
const style: Vars = {
"--duration": duration,
"--easing": easing,
"--color": color,
"--frame-color": frameColor,
} as Vars & { "--frame-color"?: string };
return (
<div className={styles.tube} style={style} aria-hidden="true">
<div className={styles.water} />
</div>
);
}06 満ちていく水の円 — 計測 累積面積 3.84% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · 【コピペOK】ローディング 画面 デザイン CSSだけ 9選
このデモが属する記事
【コピペOK】ローディング 画面 デザイン CSSだけ 9選ローディング 画面 デザインとは、サービスが開く最初の瞬間に「今準備しています」と伝える待ち画面のことです。デフォルトのスピナーでも動きますが、パステルのリングや満ちていく水のような画面にすると、同じ待ち時間が意図のあるものに見えます。コピ この記事のデモをすべて見る


