この記事の概要
2023 年 8 月 20 日開催のなごデ LT という LT イベントで発表する内容です。
Grainy Gradient1 と調べると、ザラっとした質感でフリーフォームなグラデーションが出てきます。
こういった表現をデジタルプロダクトで実施しようと思うと、どうしても画像に頼りがちです。
画像で作ると、少しだけ色を変えたいときに毎度画像ごと編集する必要があり手間がかかります。
また、ワンポイントで使うならいざしらず、背景全面に敷こうなどとすれば結構なファイルサイズ2になりそうで好ましくありません。
というわけで、サイズの軽い svg で実現してみせようという記事です。
作ったもの
ディスプレイに大きく表示しないと分かりづらいので GitHub Pages で公開しました。
背景画像だけを抜き出すとこんな感じです。
色の違いが分かりやすいようなグラフィックにしたつもりですが、実際は様々な色や形状で作れます。
作り方
コードの全体像
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"> <!-- 1. 好きな viewBox のサイズ -->
<g filter="url(#noise)"> <!-- 3. filter の用意 -->
<!-- 2. 色々なパス -->
</g>
<defs>
<filter id="noise"> <!-- 3. filter の用意 -->
<feTurbulence baseFrequency="1" numOctaves="1" stitchTiles="stitch" type="fractalNoise" result="turbulence"/> <!-- 3.1. feTurbulence -->
<feGaussianBlur in="SourceGraphic" stdDeviation="64 8" result="blur"/> <!-- 3.2. feGaussianBlur -->
<feBlend mode="color-burn" in="turbulence" in2="blur"/> <!-- 3.3. feBlend -->
</filter>
</defs>
</svg>
1. 好きな viewBox のサイズ
見本では viewBox="0 0 1024 1024"
としていますが、基本的にどんなサイズでも構いません。
ただし、実際に表示する際の幅や高さとあまりにもかけ離れたサイズを指定すると、綺麗なノイズが出ないなどの問題が起き得ます。
大きければ大きいほど良い、というものでもないので、ほどほどのサイズで指定しておきましょう。
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
</svg>
2. 色々なパス
この領域に自分の好きな色・形のパスを用意します。
今回はこんなものを用意しました。
正直言うと、どうしても後から色々微調整する必要はあるので、この段階で神経質になる必要はありません。
ここまでのコードは次のようになります。
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
+ <g>
+ <!-- 色々なパス -->
+ </g>
</svg>
3. filter の用意
先ほど作ったパスにノイズやぼかしを加えるためには filter
を使います。
今回は 1 つしか用意していませんが、複数のフィルターを用意して、それぞれのパスで filter="url(#noise1)"
, filter="url(#noise2)"
, filter="url(#noise3)"
のように適用することも可能です。
ここまでのコードは次のようになります。
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
- <g>
+ <g filter="url(#noise)">
<!-- 色々なパス -->
</g>
+ <defs>
+ <filter id="noise">
+ </filter>
+ </defs>
</svg>
3.1 feTurbulence
フラクタルノイズやタービュレントノイズを作れます。
色々な設定ができますが、次のような内容をおすすめします。
- baseFrequency
- 0.8 - 1.2 程度
- numOctaves
- 1 - 3 程度
- stitchTiles
- stitch
- type
- fractalNoise
組み合わせ方によって大きく見た目が変わるので、詳細が気になる人は MDN Docs などをどうぞ。
ここまでのコードは次のようになります。
(feTurbulence
の中に result
という属性があり、ここまでノータッチですが、後から説明します。)
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#noise)">
<!-- 色々なパス -->
</g>
<defs>
<filter id="noise">
+ <feTurbulence baseFrequency="1" numOctaves="1" stitchTiles="stitch" type="fractalNoise" result="turbulence"/>
</filter>
</defs>
</svg>
現段階での見た目は次のようになります。
……先ほど作成したパスがすべて消えて、あたり一面のノイズになってしまいましたが、大丈夫です。
3.2 feGaussianBlur
ガウスぼかしをかけられます。
in="SourceGraphic"
を指定した場合、元々の画像をぼかす、と考えてもらえれば大丈夫です。
stdDeviation
はぼかし半径です。
ただ、水平ぼかし量と垂直ぼかし量をそれぞれ設定できます。
別の値を設定しておいた方がより表情豊かな見た目になると思います。
今回は stdDeviation="64 8"
と設定しました。
こちらも詳細が気になる人は MDN Docs などをどうぞ。
ここまでのコードは次のようになります。
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#noise)">
<!-- 色々なパス -->
</g>
<defs>
<filter id="noise">
<feTurbulence baseFrequency="1" numOctaves="1" stitchTiles="stitch" type="fractalNoise" result="turbulence"/>
+ <feGaussianBlur in="SourceGraphic" stdDeviation="64 8" result="blur"/>
</filter>
</defs>
</svg>
現段階での見た目は次のようになります。
ぼかしがかかった代わりにノイズが完全に消滅しましたが、これも現段階では大丈夫です。
3.3 feBlend
ここまで、ノイズだけになったりぼかしだけになったりで、狙った通りの見た目になりませんでした。
今回の feBlend
を使うことで解消します。
見本のコードで書かれるだけ書かれていて触れられていなかった result
とともに解説します。
feBlend
には in
と in2
という属性があり、この 2 つに渡した内容をブレンドします。
ブレンドの方法は CSS の mix-blend-mode
と同じです。
今回は color-burn
を選びましたが、overlay
でも hard-light
でもお好きなものをどうぞ。
こちらも詳細が気になる人は MDN Docs などをどうぞ。
ここまでのコードは次のようになります。
<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#noise)">
<!-- 色々なパス -->
</g>
<defs>
<filter id="noise">
<feTurbulence baseFrequency="1" numOctaves="1" stitchTiles="stitch" type="fractalNoise" result="turbulence"/>
<feGaussianBlur in="SourceGraphic" stdDeviation="64 8" result="blur"/>
+ <feBlend mode="color-burn" in="turbulence" in2="blur"/>
</filter>
</defs>
</svg>
これで、最初に示したのと同じ見た目になりました。
最後に
見本では簡単めなコードにしましたが、複数の feBlend
を組み合わせて更に複雑な表情を作ることも可能です。
ちなみに、似たような内容で以前こんな記事も書きました。
こちらもあわせて読んでいただけたら嬉しいです。
最後まで読んでくださってありがとうございます!
X (Twitter)でも情報を発信しているので、良かったらフォローお願いします!
Devトークでお話してくださる方も募集中です!