imasashi.net

海外のウェブサイトでよくみる「要素が画面内に入ったらふわっとフェードインするあれ」の実装方法

fadein_002

最近よく見るようになりましたエフェクトの実装方法です。
海外のオシャンティーなウェブサイトは必ずといっていいほど取り入れているように思います。

fadein

デモ作りました。要するにこういうやつです。

基本的な考え方

  1. アニメーションはcss3のtransitionで制御する
  2. アニメーションの開始トリガーをjsで制御する

という感じで、css3とjsのあわせ技で頑張ります。

具体的なマークアップ

html

<div>

	<section class="fadein">
		<h2>情報設計</h2>
		<p>何かしらの説明文。何かしらの説明文。何かしらの説明文。</p>
	</section>

	<section class="fadein">
		<h2>サイトマップ</h2>
		<p>何かしらの説明文。何かしらの説明文。何かしらの説明文。</p>
	</section>

	<section class="fadein">
		<h2>ワイヤーフレーム</h2>
		<p>何かしらの説明文。何かしらの説明文。何かしらの説明文。</p>
	</section>

</div>

何の取り得も無いhtmlです。
エフェクトをかけたい単位に例えば「fadein」といったclassを加えておきます。

css

今回の一番のポイント、css3のtransitionを使います。

/* 画面外にいる状態 */
.fadein {
	opacity : 0.1;
	transform : translate(0, 50px);
	transition : all 500ms;
	}

/* 画面内に入った状態 */
.fadein.scrollin {
	opacity : 1;
	transform : translate(0, 0);
	}

前半ではデフォルトの状態を指定します。
この状態では、fadeinのclassが付与された要素は「透明度が0.1で、下方に50px移動している」状態となっています。

そして、この要素に「scrollin」というclassが付与されると、「透明度が1で、元の位置に移動している」状態(本来の表示)を指定します。

で、5行目にいるtransitionで、この間をアニメーションでつなぐ、というやり方です。
こうしておくと、「scrollinというclassが付いた瞬間にアニメーションが始まる」状態となります。

要するに、画面内に要素が入ったら

<section class="fadein">
	<h2>情報設計</h2>
		<p>何かしらの説明文。何かしらの説明文。何かしらの説明文。</p>
</section>

↓ 画面内に入ると

<section class="fadein scrollin">
	<h2>情報設計</h2>
		<p>何かしらの説明文。何かしらの説明文。何かしらの説明文。</p>
</section>

こういう変化を起こせばいい、というようにしておきます。そして、この「scrollin」を付与するトリガーを、jsで制御します。

js

$(function(){
	$(window).scroll(function (){
		$('.fadein').each(function(){
			var elemPos = $(this).offset().top;
			var scroll = $(window).scrollTop();
			var windowHeight = $(window).height();
			if (scroll > elemPos - windowHeight + 200){
				$(this).addClass('scrollin');
			}
		});
	});
});

※要jQuery。
fadeinというclassを持っている要素が、画面内に入ってさらに200pxスクロールすると、同要素にscrollinというclassを加える、ということをやっています。

7行目の「+200」は削除しても構いません。
削除すると「画面内に入った瞬間にclassが付与=アニメーションが始まる」ことになります。こうしてしまうと、画面の下の方でエフェクトが完了してしまい、気付きにくいかなぁと思って加えています。ここはいろいろ試してみつつ、お好みで決めるとよいでしょう。

ということで、一応以上で「要素が画面内に入ったらふわっとフェードインする」エフェクトはできます。
下はちょっとした応用編です。

横に並ぶ要素を左から右でややズラすには

fadein_002

要素が横に並んでいる場合、いっぺんにフェードインしても芸がないので、ちょっとずつ時間差をつけることを考えます。
デモの3セクション目はこれの例です。

やり方はいろいろあると思うのですが、今回はcss3の「transition-delay」を使いました。
jsの発火条件には手を加えずに、cssだけで制御ができてお手軽だからです。というか、個人的にjsはまだ苦手意識があるからあんまりjsをいじりたくないという理由が強いです。

css

/* 2つ目の要素に200msのdelayをかける */
#effect2 > div .fadein:nth-of-type(2) {
	-moz-transition-delay:200ms;
	-webkit-transition-delay:200ms;
	-o-transition-delay:200ms;
	-ms-transition-delay:200ms;
	}
/* 3つ目の要素に400msのdelayをかける */
#effect2 > div .fadein:nth-of-type(3) {
	-moz-transition-delay:400ms;
	-webkit-transition-delay:400ms;
	-o-transition-delay:400ms;
	-ms-transition-delay:400ms;
	}

transition-delayは、文字通りtransitionが開始するタイミングを指定するものです。いやー便利ですねcss3。
ちょっと遅延させたい要素を指定して、バカらしいですがひとつづつtransition-delayを設定しています。あんまり数が多くなければこれでも許容範囲かと。
時間差は、200msくらいがちょうどいいと感じました。400msまで間隔をあけるともっさりした印象です。

この方法の弱点

js無効だとダメ

cssでデフォルトで透明にしているため、jsが切れていると表示されません。
そのケースにも対応するなら、アニメーションもjsで制御した方がいいと思います。大企業サイトならともかく、個人サイトなどでそこまでカバーする理由は少ないので、後はポリシーの問題かと。
今回は、jsが切れているケースを考えはじめるときりがないのと、css3でアニメーションした方が今どきっぽいという理由でこちらを選択しました。

iOSではダメ

iOSではこの処理は切った方がいいです。
iOSの場合、スクロールが終わったタイミングでスクロール位置を取得するらしいので(スクロールしている「最中」は発火しない)、まともに機能しません。

htmlがちょっとだけ煩雑になる

ただの私のポリシーですが、htmlには「文章の意味と関係しないマークアップはしない」主義なのですが、今回は泣く泣くclassをつけました。
このエフェクトをつける要素をhtml側で統一して指示しておかないと、cssやjsが結構めんどくさいことになるからです。

たぶん確認環境

  • IE10 / 11(10は未確認ですが対応してるはず)
  • Firefox
  • Chrome
  • Safari

transitionが効くことが前提ですので、IE8や9はNGなはずです。