インクが滲んで現れる吹き出しInk Blot Bubble
/* 物語: 一滴が落ちる → 着地で潰れて滲みが散る → 滲みが吹き出しの形に膨らむ(ばね) →
しっぽが伸びて文字が浮かぶ → 乾いて消えループ */
.cg-sb-ink {
position: relative;
width: 264px;
padding-top: 44px;
}
/* ①落ちる一滴。落下中は縦に伸び、着地でぺしゃんと潰れる */
.cg-sb-ink-drop {
position: absolute;
left: 50%;
top: 0;
width: 14px;
height: 18px;
margin-left: -7px;
border-radius: 50% 50% 46% 46% / 62% 62% 38% 38%;
background: linear-gradient(#3D3B4A, #14131A);
animation: cg-sb-ink-drop 5s cubic-bezier(.5, 0, .8, .3) infinite;
}
/* ②本体。滲みが上端から膨らんで吹き出しになる */
.cg-sb-ink-body {
position: relative;
padding: 16px 20px;
border-radius: 18px 20px 17px 21px;
color: #F4F1EA;
background: #17161E;
transform-origin: 50% 0;
transform: scale(.12);
opacity: 0;
animation: cg-sb-ink-blot 5s cubic-bezier(.34, 1.56, .64, 1) infinite;
}
/* ③しっぽ。本体より一拍遅れて伸び上がる */
.cg-sb-ink-body::before {
content: "";
position: absolute;
left: 50%;
top: -9px;
width: 18px;
height: 12px;
margin-left: -9px;
background: #17161E;
clip-path: polygon(50% 0, 100% 100%, 0 100%);
transform-origin: 50% 100%;
transform: scaleY(0);
animation: cg-sb-ink-tail 5s cubic-bezier(.34, 1.56, .64, 1) infinite;
}
/* ④副次レイヤー: 着地で外へ散る滲み。以降は薄い染みとして残る */
.cg-sb-ink-body::after {
content: "";
position: absolute;
inset: -12px;
z-index: -1;
border-radius: 26px;
background: radial-gradient(closest-side, rgba(23, 22, 30, .36), rgba(23, 22, 30, 0) 78%);
opacity: 0;
animation: cg-sb-ink-spread 5s ease-out infinite;
}
.cg-sb-ink-text {
display: block;
font-size: 14px;
line-height: 1.65;
opacity: 0;
animation: cg-sb-ink-text 5s ease-out infinite;
}
@keyframes cg-sb-ink-drop {
0% { transform: translateY(-24px) scale(.72, 1.28); opacity: 0; }
8% { transform: translateY(-14px) scale(.78, 1.24); opacity: 1; }
26% { transform: translateY(22px) scale(.86, 1.2); opacity: 1; }
31% { transform: translateY(34px) scale(1.55, .38); opacity: .85; }
36% { transform: translateY(34px) scale(2, .14); opacity: 0; }
100% { transform: translateY(34px) scale(2, .14); opacity: 0; }
}
@keyframes cg-sb-ink-blot {
0%, 30% { transform: scale(.12); opacity: 0; }
37% { transform: scale(.62); opacity: .75; }
46% { transform: scale(1.07); opacity: 1; }
54% { transform: scale(.97); opacity: 1; }
61%, 87% { transform: scale(1); opacity: 1; }
97%, 100% { transform: scale(.12); opacity: 0; }
}
@keyframes cg-sb-ink-tail {
0%, 34% { transform: scaleY(0); }
44% { transform: scaleY(1.32); }
53% { transform: scaleY(.9); }
61%, 87% { transform: scaleY(1); }
97%, 100% { transform: scaleY(0); }
}
@keyframes cg-sb-ink-spread {
0%, 31% { transform: scale(.45); opacity: 0; }
39% { transform: scale(1.16); opacity: .9; }
58% { transform: scale(1); opacity: .32; }
87% { transform: scale(1); opacity: .18; }
100% { transform: scale(.45); opacity: 0; }
}
@keyframes cg-sb-ink-text {
0%, 48% { transform: translateY(5px); opacity: 0; }
60%, 87% { transform: translateY(0); opacity: 1; }
95%, 100% { transform: translateY(5px); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
/* 静止形: 滲み終わった吹き出し。本文が読めて吹き出しとして成立する */
.cg-sb-ink-drop,
.cg-sb-ink-body,
.cg-sb-ink-body::before,
.cg-sb-ink-body::after,
.cg-sb-ink-text { animation: none; }
.cg-sb-ink-drop { display: none; }
.cg-sb-ink-body { transform: none; opacity: 1; }
.cg-sb-ink-body::before { transform: scaleY(1); }
.cg-sb-ink-body::after { transform: scale(1); opacity: .2; }
.cg-sb-ink-text { transform: none; opacity: 1; }
}
<div class="cg-sb-ink"><span class="cg-sb-ink-drop" aria-hidden="true"></span><div class="cg-sb-ink-body"><span class="cg-sb-ink-text">インクが落ちて、滲んで、言葉になる。</span></div></div>