CSSで水滴を描く方法のメモです。きっかけは、YouTubeで観たPhotoshop Tutorial: How to Make Water Dropsという動画。Photoshopのレイヤースタイルにシャドウの効果を追加していく方法がCSSでも真似できそうに思えたので再現してみました。
See the Pen CSS waterdrops using mix-blend-mode by Kazuhiro Hashimoto (@kaz_hashimoto) on CodePen.
※素材画像: Photo by Evangeline Sarney on Unsplash
はじめに、アニメーションが付いてない方の4個の水滴の作り方の説明です。水滴を乗せるベースの画像をここではphoto.jpgとします。以下のコードで、div.waterdrops
が水滴1個になります。
<div class="photo">
<img src="photo.jpg" alt="">
<div class="waterdrops a"></div>
<div class="waterdrops b"></div>
<div class="waterdrops c"></div>
<div class="waterdrops d"></div>
</div>
水滴の領域は正方形のボックスですが、レスポンシブ対応にするため、寸法をwidth
にのみ依存するようにしてパーセント単位で指定します。コンテナーのdiv.photo
にはposition: relative
を設定しておきます。寸法などその他のプロパティの設定についてはCodePen参照。
.photo {
position: relative;
}
.waterdrops {
width: 6.25%; /* 50/800 (W) */
position: absolute;
}
ここではwidth
を6.25%にしました。これは、ベースの画像を幅800pxで表示した時にちょうどよい大きさに見える水滴の寸法50pxから算出した値です。
これだけではdiv.waterdrops
が高さを持たないので、擬似要素を使ってパディング領域を作り正方形の領域をはめ込みます。
.waterdrops::before {
display: block;
content: '';
width: 100%; /* 包含ブロックの幅 (W) */
height: 0;
padding-top: 100%; /* 包含ブロックの幅 (W) */
}
水滴の外形となる正円を作ります。
.waterdrops {
width: 6.25%;
position: absolute;
border-radius: 50%; /* 外形の円*/
}
水滴の質感をベース画像のレイヤーとのブレンドで作り出すため、背景を黒→白のグラデーションで塗ります。グラデーションの方向は左上から右下です。ブレンド時のメリハリをつけるため、黒の長さは25%まで延ばします。
background-image: linear-gradient(to right bottom, black, black 25%, white);
水滴の外側と内側にシャドウを設定します。内側のシャドウ(inset
)の位置は、左上を厚くする(下図A)、右下を厚くする(同B)など考えられますが、仕上がりはAの方が水滴に立体感が出ていい感じだったのでここではAのパターンで設定します。ちなみに、参考にした動画Photoshop Tutorial: How to Make Water Dropsでは、レイヤー効果の「シャドウ(内側)」をBのように右下を厚くするように設定していました。
box-shadow: 10px 10px 14px red, inset 2px 2px 5px blue; /* A */
box-shadow: 10px 10px 14px red, inset -2px -2px 5px blue; /* B */
シャドウの色をほぼ黒1にして不透明度を下げます。
box-shadow: 10px 10px 14px rgba(4,0,0,0.3),
inset 2px 2px 5px rgba(4,0,0,0.3);
.waterdrops::after {
display: block;
content: '';
width: 12%; /* 6/50 */
height: 12%;
border-radius: 50%;
position: absolute;
top: 20%;
left: 20%;
background: rgba(255,255,255,0.9);
}
div.waterdrops
にmix-blend-mode: overlay
を設定して、ベース画像のレイヤーと水滴のレイヤーをブレンドします。最後に水滴の表示位置を調整して出来上がり。
.waterdrops {
width: 6.25%;
position: absolute;
border-radius: 50%;
background-image: linear-gradient(to right bottom, black, black 25%, white);
box-shadow: 10px 10px 14px rgba(4,0,0,0.3), inset 2px 2px 5px rgba(4,0,0,0.3);
mix-blend-mode: overlay;
}
.waterdrops.a {
top: 60%;
left: 55%;
}
水滴をアニメーションで動かす
JavaScriptを使って水滴に動きを加えてみましょう。アニメーションはGSAPで作成します。
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/gsap.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/3.10.4/EasePack.min.js'></script>
準備として、水滴のdiv要素を簡単に生成できるよう関数にしておきます。
function createWaterdrop() {
const el = document.createElement('div');
el.classList.add('waterdrops');
return el;
}
使い方はこんな感じ。生成した水滴のdivに位置をセットしてコンテナーdiv.photo
の子要素に追加します。
const photo = document.querySelector('.photo');
let d = createWaterdrop();
d.style.top = '5%';
d.style.left = '45%';
d.style.opacity = 0;
photo.appendChild(d);
ここでは、一番上のオレンジにかかる水滴の動きを実現するコードを説明します。このアニメーションは2つの動きで構成されます。
- 水滴が縦に伸びながら上から下へ流れる動き
- 水滴が縮んで斜めになって止まるまでの動き
それぞれをgsap.to() tweenに分けてtimelineを構成すると、
let tl = gsap.timeline();
tl.to(d, {scaleY: 1.5, scaleX: 0.7, opacity: 1,
x: '10%', y: '150%', duration: 1.5})
.to(d, {scale: 1, skewX: -10, skewY: -10, y: '200%', duration: 2.5});
(GIFアニメーションです。Firefox向け直リンクはこちら)
2つの動きの境目が滑らかにつながりません。1つ目のtweenが終了した所で一旦止まってから2つ目のtweenが開始するように見えて人工的な感じがしてしまいます。これは、easing関数がそれぞれのtweenで完結するためです。
tween1 | tween2 | |
---|---|---|
easing | 速い→減速→停止 | 速い→減速→停止 |
「でろ〜ん」とした感じの動きにするために、1つのeasing曲線上を2つのtweenが連続して動くようにしたい。そこで、gsap.to()
のkeyframes
プロパティを使います。2つのtweenに指定していたパラメーターのオブジェクトを配列にしてkeyframes
に設定し、全体は1つのgsap.to()
tweenにまとめます。easing関数はSlowMoプラグインのslow()
関数を使ってみました。
keyframes | [tween1, tween2] |
---|---|
easing | 速い→減速→等速→加速→停止 |
easing曲線はこちらで確認できます。
gsap.to(d, {keyframes: [{scaleY: 1.5, scaleX: 0.7, opacity: 1,
x: '10%', y: '150%', duration: 1.5}, {scale: 1, skewX: -10, skewY: -10, y: '200%', duration: 2.5}],
ease: 'slow(0.7, 0.4, false)'
});
(GIFアニメーションです。Firefox向け直リンクはこちら)
-
このRGB値はHSB値 H=0°, S=100%, B=1%にほぼ相当します。Photoshopでレイヤー効果のスタイルパネルの「ドロップシャドウ」や「シャドウ(内側)」に対する描画色の初期値に使用されています。 ↩