CSS と SVG で曇りガラスのような効果を作る

Category : CSS, SVG

2011年の9月に CSS と SVG filter でガラスっぽい効果をつける というのを書きましたが、これは Firefox のみを対象としたものでした。
そこで今回はできるだけ多くのブラウザに対応したものを作ってみます。

完成品

Frosted glass effect with CSS & SVG

Frosted glass effect with CSS & SVG

背景画像には WetFoto.com による #246 Wetlook with Beautiful Brunette in Leggings and Jacket. Girl in black jacket, white wetlook leggings and skirt in boots, get wet fully clothed in the sea. を使用しています (リンク先は Flickr です)。
この画像は CC BY-NC-SA 2.0 でライセンスされています。

デスクトップブラウザは IE 10, Firefox 19, Chrome 25, Opera 12.14 (Presto) で期待通りに表示されます。
IE 8, 9 はぼかし効果なしです。IE 7 以下向けには書いていないので未確認。
Safari 6 は未確認。

モバイルブラウザは Android 4.1 で確認したところ、Firefox 19, Opera Mobile 12.1 (Presto) で期待通りに表示されます。
Chrome for Android 25 はぼかし効果はかかるものの、background-position: fixed; の挙動がおかしくてちゃんと表示できません。
Android Browser ではぼかし効果なしで表示されます。
Mobile Safari は未確認。

完成コードの主な部分は次のようになっています。

<div class="header glass">
  <!--[if lt IE 9]>
    <div class="legacy-ie-fix"></div>
  <![endif]-->
  <h1>WET</h1>
</div>
html {
  background-image: url("bg.jpg");
  background-position: center bottom;
  background-attachment: fixed;
  background-size: cover;
  height: 100%;
  font-size: 100%;
}

body {
  margin: 0;
}

.glass {
  position: relative;
  border-bottom: 1px solid;
  border-bottom-color: #ccc;
  border-bottom-color: rgba(255, 255, 255, 0.2);
  background-color: rgba(255, 255, 255, 0.2);
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
}

.glass::before {
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
  width: 100%;
  height: 100%;
  background-image: url("data:image/svg+xml,(SVG Image Data URI)"), url("bg.jpg");
  background-position: center bottom;
  background-attachment: fixed;
  background-size: cover;
  content: "";
  filter: url("data:image/svg+xml,(SVG Filter Data URI)#blur");
  -webkit-filter: blur(5px);
  filter: blur(5px);
}

.glass .legacy-ie-fix {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #fff;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=20)";
}

.glass h1 {
  position: relative;
  margin: 0;
  color: #fff;
  color: rgba(255, 255, 255, 0.3);
  font-size: 200px;
  font-weight: normal;
  font-family: "Megrim", sans-serif;
  line-height: 1.2;
  text-align: center;
  -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=50)";
}

@media only screen {
  .glass h1 {
    -ms-filter: "none";
  }
}

CSS の部分で「SVG Image Data URI」と書かれているものは次のような SVG です。

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1600" height="1066">
  <defs>
    <filter id="blur">
      <feGaussianBlur stdDeviation="5"/>
    </filter>
  </defs>
  <image xlink:href="http://unformedbuilding.com/demo/2013/frosted-glass-effect/bg.jpg" width="1600" height="1066" filter="url(#blur)"/>
</svg>

「SVG Filter Data URI」と書かれているものはこれ。前のものから image 要素を消したものですね。

<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>
    <filter id="blur">
      <feGaussianBlur stdDeviation="5"/>
    </filter>
  </defs>
</svg>

解説みたいなもの

基本的には以前作ったものと同じなんですが、複数のブラウザに対応するためにやったことについて説明してみます。

まず、フィルタ効果と対応ブラウザについて。

  • IE 8~9: なし
  • IE 10: SVG Filter
  • Firefox 19: SVG Filter, HTML への SVG Filter
  • Chrome 25: CSS Filter (-webkit-filter)
  • Opera 12.14: SVG Filter

IE 9 以下には DX Filter がありますが、ぼかし効果の挙動がよく分からないので諦めました。

.glass::before の部分。
background-imagebg.jpg を読み込んでフィルタをかけた SVG と bg.jpg を指定している理由について。

はじめはこの SVG だけで大丈夫だと思っていたんですが、CSS で読み込む SVG の外部リソースはセキュリティの関係上 Firefox と Chrome では無視されます。IE 9, 10 と Opera は大丈夫。
これがどうなるのかというと、Firefox と Chrome では何もない透明な SVG が読み込まれます。IE 10 と Opera では、画像にフィルタをかけた SVG 画像が読み込まれます (IE 9 はフィルタなし)。

複数指定の background-image は書いた順に上位のレイヤーとなるので、IE 9, 10 と Opera では2つ目の指定 url("bg.jpg") は最初に読み込んだ SVG に覆い隠されて見えなくなります。
そして image 要素が無視される Firefox と Chrome では、2つ目の画像が表示されます (実際には透明な SVG 画像が上にかぶさってますが)。

IE 10 と Opera は読み込む SVG でフィルタを適用済み、且つ CSS からフィルタをかけることができません。
Firefox は Data URI として読み込んだ SVG フィルタを適用し、背景画像をぼかします。
Chrome も同様に CSS フィルタを適用します。

以上がモダンブラウザへの対応です。
あくまでも現状での動作なので、IE 11 で SVG の外部リソースが無視されるようになったりしたらアウトです。

次は IE 8 への対応。
IE 8 は rgba() 指定に対応していないので、DX Filter による不透明度指定でそれっぽくしておきます。
ただし、DX Filter は擬似要素に適用できませんので、IE 8 向けに空の div を作ってあげます。他のブラウザに影響を与えないようにコンディショナルコメントによる指定も行います。
また、IE 8 はダブルコロンの擬似要素セレクタに対応していないので、.glass::before の部分にあるルールセットを無視しますが、あんまり関係ないのでそのままで。
あとは他のブラウザと似たような感じになるように背景色と不透明度調整のフィルタをかけます。

.glass h1 の部分ですが、文字を半透明にするためにここでも DX Filter を使っています。
が、これは IE 9 も解釈してしまうので、その直後に IE 9 では取り消すよう指定を行います。
IE 8 が @mediaonly キーワードを解釈しないことを利用して -ms-filter の指定を取り消します。

他の仕組みはほとんど前と同じなのでそちらを参照してください。

Trackbacks & Pingbacks

Leave a Reply