背景画像だけをフェードインで表示させる方法

フェードで出現
昨日、画面全体が表示されてから数秒後、浮き出るように画像を表示するのページで説明したように、横幅1500ピクセル以上のディスプレイでこのブログを表示すると鳳凰の画像がふわっと現れる。(フェードインという)

仮にこの画像をimg要素としてフェードインさせるのならば、jQueryのfadeInメソッドを使用すれば最も簡単に実装できるだろう。
参考URL:jQuery日本語リファレンス・fadeIn

しかし、実はそのやり方では問題が発生する。
今回のようにコンテンツ幅より横幅の大きい画像をimg要素として出現させると、本来は以下の画像のようなコンテンツ幅だったのが、
本来のコンテンツ幅
img要素を出現させることによって以下のようにコンテンツ幅が広がってしまう。(未検証だがおそらく)
img要素出現後のコンテンツ幅
コンテンツ幅が上画像のように広がると、それに応じてブラウザの横スクロールバーが出てしまったりと別の新たな問題が発生してしまうことになる。
これではまずい。

それを避けるためには、画像をimg要素ではなくCSSの背景画像として表示させることになるだろう。
しかしここでも問題がある。
上記のjQueryのfadeInメソッドやanimateメソッドは背景画像だけをフェードインすることができないという点である。
その要素ごとフェードインさせることしかできない。

というわけで、今回はCSSの背景画像をフェードインさせる際の問題点とその解決法を解説します。

背景画像をフェードインさせるときに発生する問題点

CSSの背景画像をフェードインさせる手順のイメージとしては以下のようになります。

1、まず、フェードインさせる画像が以下のような画像だとします。
フェードインさせる背景画像
2、これを例えばdiv要素などのCSSの背景画像として設定し、
背景画像として設定
3、そのdiv要素を透明度0にしておく。
要素ごと透明度を0に設定
4、そしてdiv要素の透明度をfadeOutメソッドやanimateメソッドによって0から1にすればよい。
背景画像として設定

しかしここで発生する問題点は、このdiv要素内にコンテンツがある場合、そのコンテンツも上記3の段階で透明になってしまうという点である。
要素内のコンテンツも透明になる
今回の目的はあくまでも「背景画像だけをフェードインさせる」というものなので、中にあるコンテンツまでもが透明になってはまずい。
ではどうするか?

上記問題点の解決法

解決法の手順としては以下のようになります。

1、背景画像を設定したdivをコンテンツとは別レイヤーにして背後に重ねる。
別レイヤーにして背後に重ねる
2、コンテンツのレイヤーは背景色を設定せず透明にしておき、下のレイヤーは背景画像ごと透明にする。
下のレイヤーを透明にする
3、そして下のレイヤーだけをfadeInメソッドやanimateメソッドでフェードイン表示させる。
下のレイヤーをフェードイン

このやり方のポイントは、2つのレイヤーを入れ子にしないことである。
入れ子にしてしまうと透明度の設定やフェードインの設定が両方に及んでしまうためです。(文末にある追記参照)
CSSのpositionプロパティとz-indexを使用して重ねてください。

具体的なソースの例

では、上記の手順を実現するためのソースの例を書いてみます。

1、コンテンツのレイヤーの背景色を透明にする。
<div class="contents-layer"></div>
.contents-layer{
  background : transparent; /* 実際には記述しなくても初期値がtransparentである */
}
2、フェードインさせるレイヤーをコンテンツのレイヤーの背後にセット。さらに透明にしておく。(上記のように入れ子にしてはいけない)
<div class="fade-layer"></div>
<div class="contents-layer"></div>
.fade-layer{
  width : ***px; /* contents-layerと同じ大きさにする */
  height : ***px; /* contents-layerと同じ大きさにする */
  background : url(表示させる画像のパス) no-repeat 0 0;
  position : absolute;
  left : **px; /* contents-layerと同じ位置に合わせる */
  top : **px; /* contents-layerと同じ位置に合わせる */
  z-index : -1;
  opacity : 0;
}
3、JavaScriptによって下のレイヤーをフェードインさせる。(fadeInメソッドでの例)
$('.fade-layer').fadeIn();
(参考)fadeInメソッドではなくanimateメソッドの場合は以下のようになる。(フェードイン速度が800ミリ秒の場合)
$('.fade-layer').animate({
  'opacity' : '1'
}, 800);

お好きなほうのやり方でどうぞ。

なお、上記手順2で「contents-layerと同じ大きさにする」という点で、仮にcontents-layerの横幅や縦幅が可変の場合(コンテンツによって変化する場合)はJavaScriptによってその大きさを取得し、手順2のCSS設定もJavaScript側で行ってしまえば良いでしょう。

問題点のところで説明したように入れ子にしないことが前提なので、空っぽである下のレイヤーを上のレイヤーの大きさに合わせられるかがミソになります。

追記:と、ここまで全部書いてから思いましたが、入れ子にしたとしても中のレイヤーをopacity : 1 !important;としておけば、下のレイヤーを透明にしても問題ないような気がします。(未検証)