LoginSignup
7
4

More than 5 years have passed since last update.

WebKit ではSVGグラデーションを `fill-opacity` を持った要素に適用すると色味がくすむ

Last updated at Posted at 2017-05-26

WebKit(Mac版のSafari含む)では fill-opacity を設定した要素にSVGグラデーションを適用すると色味がくすんでしまいます。
SVGグラデーションを透明化する場合には、 stop-opacity を用いるか、塗りと線のパスを分けた上で塗りのパスに opacity を設定する必要がありそうです。

なお、iOS版Safariでは問題ないもよう(なぜだ)。

現象確認用のデモ

以下の様なSVGで現象が発生します。

<svg viewBox="0 0 300 200">
  <defs>
    <linearGradient id="g0">
      <stop offset="0%" stop-color="red"></stop>
      <stop offset="50%" stop-color="green"></stop>
      <stop offset="100%" stop-color="blue"></stop>
    </linearGradient>
  </defs>
  <circle cx="50%" cy="50%" r="33%" fill="url(#g0)" fill-opacity=".67"></circle>
</svg>

デモURL: https://codepen.io/haribote/pen/BREjKV?editors=1100#0

スクリーンショット 2017-05-26 13.17.32.png

↑はデモをSafariで開いたキャプチャーです。
お分かりいただけただろうか…?
方法は違えどすべて同じ透明度を指定しているにもかかわらず fill-opacity を設定しているパターンのみ色味がくすんでしまっています。

ちなみにSVGの <linearGradient /><radialGradient /> には color-interpolation 属性で色空間を指定することができますが明示的に sRGB を指定してもダメでした。

対応方法いろいろ

stop-opacity を用いる

<svg viewBox="0 0 300 200">
  <defs>
    <linearGradient id="g1">
      <stop offset="0%" stop-color="red" stop-opacity=".67"></stop>
      <stop offset="50%" stop-color="green" stop-opacity=".67"></stop>
      <stop offset="100%" stop-color="blue" stop-opacity=".67"></stop>
    </linearGradient>
  </defs>
  <circle cx="50%" cy="50%" r="33%" fill="url(#g1)"></circle>
</svg>

グラデーションを適用する要素に透明度を指定するのではなく、グラデーション定義側に透明度を指定します。
定義したグラデーションの使い方が全ての適用要素において同じなのであればこの方法でも良さそうです。

しかし、 stop-opacity は本来、透明度のグラデーションを設定するための属性・スタイル(不透明から透明にしたい、など)です。
なので要素ごとの塗りの透明度とグラデーション定義自体の透明度はやはり別に設定したいといった場合がおそらく多く、そういった場合にこの方法を用いることはできません。

opacity を用いる

<svg viewBox="0 0 300 200">
  <defs>
    <linearGradient id="g2">
      <stop offset="0%" stop-color="red"></stop>
      <stop offset="50%" stop-color="green"></stop>
      <stop offset="100%" stop-color="blue"></stop>
    </linearGradient>
  </defs>
  <circle cx="50%" cy="50%" r="33%" fill="url(#g2)" stroke="none" opacity=".67"></circle><!-- 塗りを適用するパス -->
  <circle cx="50%" cy="50%" r="33%" fill="none"></circle><!-- 線を適用するパス -->
</svg>

次に考えられるのが、グラデーションを適用する要素に opacity を設定する方法です。
ただ opacity は要素丸ごと、すなわち塗りも線も一緒くたに透明化してしまいます。
したがって塗りにだけ透明度を指定したい場合は、上記コードのように塗りを適用するパスと線を適用するパスを分けて書く必要があります。

うん、本当はそんなことしなくて良いように fill-opacity があるはずなんだけどね…。

7
4
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
7
4