23
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CSSで水滴を描く

Last updated at Posted at 2022-05-01

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個になります。

html
<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参照。

css
.photo {
  position: relative;
}

.waterdrops {
  width: 6.25%;  /* 50/800  (W) */
  position: absolute;
}

ここではwidthを6.25%にしました。これは、ベースの画像を幅800pxで表示した時にちょうどよい大きさに見える水滴の寸法50pxから算出した値です。
これだけではdiv.waterdropsが高さを持たないので、擬似要素を使ってパディング領域を作り正方形の領域をはめ込みます。

css
.waterdrops::before {
  display: block;
  content: '';
  width: 100%; /* 包含ブロックの幅 (W) */
  height: 0;
  padding-top: 100%;  /* 包含ブロックの幅 (W) */
}

水滴の外形となる正円を作ります。

css
.waterdrops {
  width: 6.25%;
  position: absolute;
  border-radius: 50%; /* 外形の円*/
}

水滴の質感をベース画像のレイヤーとのブレンドで作り出すため、背景を黒→白のグラデーションで塗ります。グラデーションの方向は左上から右下です。ブレンド時のメリハリをつけるため、黒の長さは25%まで延ばします。

background-image: linear-gradient(to right bottom, black, black 25%, white);

drop1.png
水滴の外側と内側にシャドウを設定します。内側のシャドウ(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 */

box-shadow.png
シャドウの色をほぼ黒1にして不透明度を下げます。

box-shadow: 10px 10px 14px rgba(4,0,0,0.3),
    inset 2px 2px 5px rgba(4,0,0,0.3);

drop3.png
水滴の左上に小さな光の点を付けます。

css
.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);
}

drop4.png
div.waterdropsmix-blend-mode: overlayを設定して、ベース画像のレイヤーと水滴のレイヤーをブレンドします。最後に水滴の表示位置を調整して出来上がり。

css
.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%;
}

drop5.png

水滴をアニメーションで動かす

JavaScriptを使って水滴に動きを加えてみましょう。アニメーションはGSAPで作成します。

html
<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要素を簡単に生成できるよう関数にしておきます。

javascript
function createWaterdrop() {
  const el = document.createElement('div');
  el.classList.add('waterdrops');
  return el;
}

使い方はこんな感じ。生成した水滴のdivに位置をセットしてコンテナーdiv.photoの子要素に追加します。

javascript
const photo = document.querySelector('.photo');

let d = createWaterdrop();
d.style.top = '5%';
d.style.left = '45%';
d.style.opacity = 0;
photo.appendChild(d);

ここでは、一番上のオレンジにかかる水滴の動きを実現するコードを説明します。このアニメーションは2つの動きで構成されます。

  1. 水滴が縦に伸びながら上から下へ流れる動き
  2. 水滴が縮んで斜めになって止まるまでの動き

それぞれをgsap.to() tweenに分けてtimelineを構成すると、

javascript
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向け直リンクはこちら)
drop-tween1.gif
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曲線はこちらで確認できます。

javascript
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向け直リンクはこちら)
drop-tween2.gif

  1. このRGB値はHSB値 H=0°, S=100%, B=1%にほぼ相当します。Photoshopでレイヤー効果のスタイルパネルの「ドロップシャドウ」や「シャドウ(内側)」に対する描画色の初期値に使用されています。

23
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?