今回はWebGLやJavaScriptを用いずにSVGのfilterを使ってCSSだけで画像のように画像の海の部分に波の動きをつける方法を解説していきます。

波の動きをつける用に海の画像を用意する

1年くらい前に江ノ島にいった時の画像を使います。もしなかなか外に出られなくて海の画像が用意できない場合はこちらの画像を使ってみてください。

画像を準備したらphotoshopなどで画像を切り抜いて海の部分だけを残した画像を作ってみましょう。

このような感じで海の部分だけを切り抜きます。

切り抜いた画像がこちらです。画像編集できない場合はこちらを使ってみてください。これで素材が揃いました。

HTMLとCSSで2枚の画像を重ねる

最初の画像と海部分だけ切り抜いた画像を重ねて一枚の画像に見えるようにします。

HTML

<div class="sample">
    <div class="bg">
        <div class="sea" />
    </div>
</div>

CSS

.sample {
    width: 700px;
    height: 525px;
    overflow: hidden;
    position: relative;
  }
  .bg {
    background-image: url(https://contents.crop-cream.com/img/enoshima.jpg);
    width: 110%;
    height: 110%;
    top: -5%;
    left: -5%;
    position: absolute;
    background-size: cover;
  }
  .bg .sea {
    position: absolute;
    background-image: url(https://contents.crop-cream.com/img/enosea.png);
    width: 100%;
    height: 100%;
    filter: url(#turbulence);
    background-size: cover;
  }

SVG Turbulence Filterを使用して波の動きをつける

<feTurbulence>

今回は<feTurbulence>というSVGのフィルターを使用します。雲とかマーブル模様のようなフィルターがかかります。マーブル模様のぐにゃっとなるのをノイズという言い方をしてるみたいです。

attributeについて

baseFrequency: ノイズの荒さを調整できます。

numOctaves: ノイズのオクターブ。数値が大きくなると模様が複雑な形になる。

seed: 乱数を設定するときの開始数値。

stitchTiles: タイルのつなぎ目の処理の指定。stitchかnoStitchを選ぶ。デフォルトはnoStitch。

type: noise関数かturbulence関数のどちらを使用するか指定。

<feDisplacementMap>

画像を変位させるフィルター。

attributeについて

scale: 変位スケール因子。0だと何も変化をあたえなくなる。

in: フィルタが適用される要素のグラフィック内容を指定。デフォルトはSourceGraphic。

<svg>
     <filter id="turbulence" x="0" y="0" width="100%" height="100%">
          <feTurbulence id="sea-filter" numOctaves="1" seed="3" baseFrequency="0.02 0.06" />
          <feDisplacementMap scale="10" in="SourceGraphic" />
     </filter>
</svg>

上記のようなコードでフィルターが作られます。次にこのフィルターを動かして波のような動きをつけます。

<animate>でフィルターに動きをつける

<animate>タグはSVGの要素の属性をkeyframesのように時間経過で変化させることができます。今回は<feTurbulence>のbaseFrequencyの値を変化させて波の動きをつけていきます。

<svg>
     <filter id="turbulence" x="0" y="0" width="100%" height="100%">
          <feTurbulence id="sea-filter" numOctaves="1" seed="3" baseFrequency="0.02 0.06" />
          <feDisplacementMap scale="10" in="SourceGraphic" />
          <animate
            xlink:href="#sea-filter"
            attributeName="baseFrequency"
            dur="60s"
            keyTimes="0;0.5;1"
            values="0.02 0.06;0.04 0.08;0.02 0.06"
            repeatCount="indefinite"
          />
      </filter>
</svg>

<feTurbulence>のbaseFrequencyの値を0.02 0.06から0.04 0.08に変化させてまた元に戻すというのを繰り返します。

CSSで海だけの画像にSVGのフィルターを適用する

フィルターをつけるcssを追加します。filter: url(#turbulence);

CSS

  .bg .sea {
    position: absolute;
    background-image: url(https://contents.crop-cream.com/img/enosea.png);
    width: 100%;
    height: 100%;
    background-size: cover;
    filter: url(#turbulence);
  }

まとめ

これで海の部分だけがぐにゃぐにゃ動くようになったと思います。SVGを使うと表現の幅が増えるので、まだ分からないことも多いですが掘り下げて使いこなせるようになりたいですね。