硝子の錦鯉
曇り硝子の向こうを錦鯉が泳ぐ。offset-pathのモーションパスで泳跡を描き、backdrop-filterの硝子とmaskの光模様が水面を作る。
曇り硝子
対応ブラウザ
| CSS機能 | Chrome / Edge | Firefox | Safari | 備考 |
|---|---|---|---|---|
| backdrop-filter | 対応 | 対応 | 対応 | 全主要ブラウザ対応 |
| offset-path | 対応 | 対応 | 対応 | モーションパス |
| mask | 対応 | 対応 | 対応 | 全主要ブラウザ対応 |
コード
表示中のコードは作品の実行に使われているものと同一ソースです。そのままコピーして試せます。
/* 硝子の錦鯉: offset-pathの泳跡、backdrop-filterの曇り硝子、
maskで淡くした水面の光模様 */
.work-glass-koi {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
background: #06131c;
}
.gk-pond {
position: absolute;
inset: 0;
background:
radial-gradient(90% 70% at 30% 20%, rgba(38, 108, 130, 0.5), transparent 65%),
radial-gradient(80% 80% at 75% 85%, rgba(16, 66, 92, 0.6), transparent 70%),
linear-gradient(160deg, #0a2532 0%, #061722 60%, #04101a 100%);
}
/* 水面の光模様。maskで中央だけ淡く残す */
.gk-caustics {
position: absolute;
inset: 0;
background-image:
repeating-radial-gradient(circle at 28% 30%,
rgba(150, 220, 235, 0.14) 0 2px, transparent 2px 42px),
repeating-radial-gradient(circle at 72% 68%,
rgba(150, 220, 235, 0.1) 0 2px, transparent 2px 56px);
-webkit-mask: radial-gradient(80% 70% at 50% 45%, #000 30%, transparent 85%);
mask: radial-gradient(80% 70% at 50% 45%, #000 30%, transparent 85%);
animation: gk-shimmer 9s ease-in-out infinite alternate;
}
@keyframes gk-shimmer {
to { background-position: 30px -20px, -40px 26px; }
}
/* ---- 錦鯉 ---- */
.gk-lane {
position: absolute;
pointer-events: none;
}
.gk-lane-1 { top: 12%; left: 6%; width: 62%; height: 60%; }
.gk-lane-2 { top: 40%; left: 34%; width: 58%; height: 52%; }
/* 泳跡はoffset-pathの閉じたパス。offset-rotate: autoで進行方向を向く */
.gk-koi {
position: absolute;
width: 92px;
height: 34px;
offset-path: path("M 40,60 C 160,10 300,40 380,90 C 420,120 380,180 280,190 C 170,200 60,170 30,120 C 15,95 20,72 40,60 Z");
offset-rotate: auto;
animation: gk-swim var(--dur, 22s) linear infinite;
}
.gk-koi-gold {
--dur: 30s;
width: 74px;
height: 28px;
animation-delay: -12s;
offset-path: path("M 30,40 C 140,90 300,20 360,80 C 400,125 330,170 220,160 C 120,150 40,130 20,90 C 10,65 12,50 30,40 Z");
}
@keyframes gk-swim {
to { offset-distance: 100%; }
}
/* 胴体: 白地に緋の斑。尾びれは::after */
.gk-koi::before {
content: "";
position: absolute;
inset: 0 18% 0 0;
border-radius: 58% 70% 70% 58% / 55% 55% 55% 55%;
background:
radial-gradient(30% 55% at 24% 35%, #e34a33 0 60%, transparent 62%),
radial-gradient(26% 50% at 58% 62%, #e34a33 0 58%, transparent 60%),
radial-gradient(18% 40% at 82% 30%, #1f2430 0 55%, transparent 57%),
linear-gradient(180deg, #f7f3ea, #d9d2c4);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.35);
}
.gk-koi-gold::before {
background:
radial-gradient(30% 55% at 30% 40%, #d98324 0 60%, transparent 62%),
radial-gradient(24% 45% at 66% 58%, #d98324 0 56%, transparent 58%),
linear-gradient(180deg, #f5ead2, #dcc79a);
}
.gk-koi::after {
content: "";
position: absolute;
top: 50%;
right: -4%;
width: 34%;
height: 130%;
translate: 0 -50%;
clip-path: polygon(0 50%, 100% 0, 78% 50%, 100% 100%);
background: linear-gradient(90deg, #e8e0d0, rgba(232, 224, 208, 0.35));
transform-origin: left center;
animation: gk-tail 0.9s ease-in-out infinite alternate;
}
.gk-koi-gold::after {
background: linear-gradient(90deg, #ecd9ab, rgba(236, 217, 171, 0.35));
}
@keyframes gk-tail {
from { transform: rotate(-14deg); }
to { transform: rotate(14deg); }
}
/* ---- 波紋 ---- */
.gk-ripple {
position: absolute;
width: 40px;
aspect-ratio: 1;
border: 1.5px solid rgba(180, 230, 240, 0.35);
border-radius: 50%;
animation: gk-ripple 5s ease-out infinite;
}
.gk-r1 { top: 24%; left: 22%; }
.gk-r2 { top: 62%; left: 70%; animation-delay: -2.5s; }
@keyframes gk-ripple {
from {
transform: scale(0.2);
opacity: 0.9;
}
to {
transform: scale(3.4);
opacity: 0;
}
}
/* ---- 曇り硝子 ---- */
.gk-glass {
position: absolute;
inset: 14% 20%;
z-index: 10;
border: 1px solid rgba(255, 255, 255, 0.28);
border-radius: 14px;
background:
repeating-linear-gradient(115deg,
rgba(255, 255, 255, 0.045) 0 3px, transparent 3px 9px),
linear-gradient(135deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.03));
backdrop-filter: blur(9px) saturate(135%) brightness(1.08);
-webkit-backdrop-filter: blur(9px) saturate(135%) brightness(1.08);
}
.gk-glass-label {
position: absolute;
right: 12px;
bottom: 8px;
color: rgba(255, 255, 255, 0.4);
font-size: 11px;
letter-spacing: 0.2em;
}
/* backdrop-filter非対応環境では半透明の磨り硝子風にフォールバック */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
.gk-glass {
background: rgba(210, 230, 240, 0.55);
}
}
/* 動きへの配慮: 停止し、CSSのみのチェックボックスでオプトイン再生 */
@media (prefers-reduced-motion: reduce) {
.work-glass-koi * {
animation-play-state: paused !important;
}
.work-glass-koi .motion-optin {
display: inline-flex;
}
.work-glass-koi:has(.motion-optin input:checked) * {
animation-play-state: running !important;
}
}