Unformed Building

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

公開:
更新:

パーマリンク

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

完成品

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でライセンスされています。

背景画像にはBeryl Chanによる「Bunny - Rainy」を使用しています(リンク先はFlickrです)。
この画像はパブリックドメインです。

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

モバイルブラウザはAndroid 4.1で確認したところ、Firefox 19, Opera Mobile 12.1で期待通りに表示されます。
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の指定を取り消します。

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


2020年1月11日 追記:
当初「#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.」という写真を使っており、記事の公開時点では、その画像はCC BY-NC-SA 2.0でライセンスされていました。
しかし、現在ではAll rights reservedに変更されているため、デモで使用している画像と、記事内の画像を差し替えました。