iOSでbackground-blend-modeがうまく効かないので、mix-blend-modeに変更したら上手くいった

## これは何

SVGを使ってノイズの背景を作る際に`background-blend-mode`を使っていたらiOSで表示が崩れてしまったので、`mix-blend-mode`にしたらうまく行ったよというメモです。

## 要点

要点はこんな感じです。

1. SVGで生成したノイズの色味調整にCSSの`background-blend-mode`を使用していた
1. iOSで検証してみたら色味調整がうまくいかず、ノイズがカラフルになっていた
1. 調べてみると、iOSでは`background-blend-mode`と`background-repeat: repeat`を一緒に使うと効かなくなるらしい..
    - Ref [ios - CSS: A background-blend-mode fallback for iPhone Safari - Stack Overflow](https://stackoverflow.com/questions/35452263/css-a-background-blend-mode-fallback-for-iphone-safari)
1. -> 色味の調整を`mix-blend-mode`に変更したら上手くいきました:white_flower:

### 最終的に作ったSVG

```xml
<svg height="200" viewBox="0 0 200 200" width="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <filter id="noise">
    <feTurbulence
      baseFrequency="0.3"
      numOctaves="3"
      stitchTiles="stitch"
      type="fractalNoise"
    />
  </filter>
  <g>
    <rect fill="#EDEEEE" height="100%" width="100%"/>
    <rect style="mix-blend-mode: overlay;" filter="url(#noise)" height="100%" width="100%"/>
    <rect style="mix-blend-mode: color;" fill="#EDEEEE" height="100%" width="100%"/>
  </g>
</svg>
```

## 解説

### 【前提】SVGでノイズを作る

まず、SVGで`feTurbulence`を使って簡単にノイズを生成することができます。

<p class="codepen" data-height="300" data-default-tab="result" data-slug-hash="jOdgZbY" data-user="kabechiyo" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/kabechiyo/pen/jOdgZbY">
  Noise</a> by kabechiyo_shunkaaizawa (<a href="https://codepen.io/kabechiyo">@kabechiyo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/feTurbulence

これを活用して、よく見る「ざらっとしたテクスチャ」を表現しようとしました。

もちろんこのままの色が混ざった状態では使えないので、ここから色味を調整していきます。

### `background-blend-mode`で色味を調整してみる

Figmaで色々試してみたところ、「①グレーの下地のレイヤー」の上に`overlay`で「②ノイズのレイヤー」を重ね、さらに`color`で「③グレーの色調整レイヤー」を重ねるとイメージ通りのテクスチャになることがわかりました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/0fed54a4-6ebc-7ce9-5a64-dc289acd5c62.png)

早速これをCSSで再現してみます。
大体以下の手順です

1. HTMLで適当なコンテナとdivを用意する
1. コンテナに背景色を指定する
1. divをコンテナいっぱいに広げ、`background`にノイズのSVGと背景色と同じ色を指定する
1. さらにdivに`background-blend-mode: overlay, color;`を指定し、色味を調整する

```html
<section>
  <div class="inner"></div> <!--  ノイズ用のdiv  -->
</section>
```

```css
section {
  background-color: #EDEEEE;
}

.inner {
  background-blend-mode: overlay, color;
  background:
    url(#{image_url('../image/noise.svg')}),
    linear-gradient(#EDEEEE, #EDEEEE);
  }
```

この方法でも上手くいっているかのように見えたのですが、iOSで実機検証してみると`background-blend-mode`が効いていませんでした..

![ノイズのスクリーンショット。iOS以外ではグレースケールのノイズが表示される。iOSではノイズが強く、色も赤や緑など様々な色が混ざっている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/20258e79-4f00-1b6d-7854-116b9114c96b.png)

調べてみると、iOSでは`background-blend-mode`と`background-repeat: repeat`を一緒に使うと効かなくなるらしいです

https://stackoverflow.com/questions/35452263/css-a-background-blend-mode-fallback-for-iphone-safari

### 色味の調整を`mix-blend-mode`に変更する

ノイズを背景に敷き詰めたい関係上、`background-repeat: repeat`を外すことはできなかったので、`background-blend-mode`を使わないで実現する方法を考えました。

結論、`mix-blend-mode`を使うとよりシンプルにかける&iOSでも崩れなかったのでこちらにしました。
作成したSVGはこんな感じです。

SVG内にrectを3つ作成し、それぞれを「背景」「ノイズ」「色味調整」にしています

まず背景のrectにベースとなる色を指定し、その上にノイズを`mix-blend-mode: overlay`で乗せます。
さらに色味調整用のrectに色を指定して`mix-blend-mode: color`で乗せています。

![グレースケールのノイズの画像。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/577501/c080e904-d6f9-5033-93e3-ca34a547f935.png)

```xml
<svg height="200" viewBox="0 0 200 200" width="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <filter id="noise">
    <feTurbulence
      baseFrequency="0.3"
      numOctaves="3"
      stitchTiles="stitch"
      type="fractalNoise"
    />
  </filter>
  <g>
    <rect fill="#EDEEEE" height="100%" width="100%"/> <!-- 背景 -->
    <rect style="mix-blend-mode: overlay;" filter="url(#noise)" height="100%" width="100%"/> <!-- ノイズ -->
    <rect style="mix-blend-mode: color;" fill="#EDEEEE" height="100%" width="100%"/> <!-- 色味調整 -->
  </g>
</svg>
```