この記事は、http://css-tricks.com/ の Chris Coyier の許可を得て、翻訳しています。一部変更して翻訳している部分もある場合があります。オリジナルの記事はここよりご覧いただけます。

先日「黒の画面上に文字が飛び込んできて、その下にあった画像が明らかになる」と言うようなコマーシャルを目にしました。視覚的にもとてもクールでしたし、それを見ていたらWebKitに-webkit-background-clipと言うテキストを通して背景を表示させるプロパティがあることを思い出しました。なので、似たような効果を再現することが出来るかどうか試してみようと思います。可能だとは思いますが幾つか興味深い問題点もありそうです・・・。

最終的にはこんな感じに仕上がる予定です:

redsonja 映画CMのようなアニメーション文字

デモはWebKitブラウザ(Safari、Mobile Safari、 Chrome)上で動作します。

まずは基本コードから

そんなに特別なものでもないんですけれどね:

.display-sweet-image-behind {
   /* fallback color */
   color: white; 

   /* overrides color with nothingness */
   -webkit-text-fill-color: transparent;

   /* remember non WebKit browsers will see all of this EXCEPT the text */
   background: url(images/zombies-making-out.jpg) no-repeat; 

   /* the magic */
   -webkit-background-clip: text;

   font: bold 100px Impact, Sans-Serif;
}
   

<div class="display-sweet-image-behind">Nom nom nom</div>
   

文字を動かす

下記の様にspanタグで全て文字を囲んでしまうのがミソです:

<div class="display-sweet-image-behind">
<span>N</span>
<span>o</span>
<span>m</span>
nom nom
</div>
   

ここで使用しているのはただのspanではありません。インラインレベル要素でラッピングしていると言うことが非常に重要なのです。これがインラインブロックやブロックだったり、何か別なものであった場合もうまく動作してはくれません=(

このspanタグのおかげで、相対配置を使っての文字移動が可能になりますね。メガ楽しみです!

.display-sweet-image-behind span {
   position: relative;
}
.display-sweet-image-behind span:nth-child(1) {
   top: -20px;
   left: -20px;
}
   

上記のコードで最初の文字が上部左へと移動してくれるはず・・・。が!違います。失敗に終わります。ポジショニングのせいでうまく行かないようです。残念x2=(=(

試しにマージンを使ってみたら、なんとうまく行きました!やった~!やっと楽しいアニメーションの時間です。spanタグはインライン要素なので左右方向へのマージンは使えますが、上下方向には効果がありません。

.display-sweet-image-behind span:nth-child(1) {
   margin-left: -100px; /* remember this will yank all the letters over this far */
}
   

Lettering.js

まぁこんな感じに進んでいますが、実際1つ1つの文字を手作業でspanタグでラップする必要があると思いますか?答えはNOです。Lettering.jsというjQueryのプラグインを使えば、文字通り一発解決してくれます。要素のセットで呼び出せば、その位置を参照するクラス名を使用してspan内の全ての文字を個別にラッピングしてくれます。

$(".display-sweet-image-behind").lettering();
   

超シンプルで超クールですね。もっと早く思い出すべきでした。

アニメーション化

今回の最終ゴールは個々の文字をアニメーション化して所定の位置へ動かすことでしたね。ゴールに向けて使用する最後のサンプルマークアップはこちらです:

<div id="poster">
        <h1>Red Sonja</h1>
        <p>Coming 2011</p>
</div>
   

これをLettering.jsというJavaScriptの一行を使って、全ての文字をspanで囲みます:

$("#poster h1, #poster p").lettering();
   

そしてその文字にtransitionを指定することにより、その「変化を指定されたプロパティ」はアニメーション化されます。これはWebKitブラウザ上のみで動作しますが、文字の動きだけなら他のブラウザでも同じような動作をするかもしれません。

#poster h1 span {
        -webkit-transition: all 2.5s;
        -moz-transition: all 2.5s;
        -o-transition: all 2.5s;
}
   

Lettering.jsで適用されるクラスはchar1やchar2などなので、これらに大きな数字のマージンを適用させて文字をページから蹴りだします。

#poster h1 span.char1 { margin-left: -1450px; }
#poster h1 span.char2 { margin-left: 200px; }
#poster h1 span.char3 { margin-left: 200px; }
#poster h1 span.char5 { margin-left: 1450px; }
#poster h1 span.char6 { margin-left: 200px; }
#poster h1 span.char7 { margin-left: 200px; }
#poster h1 span.char8 { margin-left: 200px; }
#poster h1 span.char9 { margin-left: 200px; }
   

文字が動き始めるまでに少し時差を加えてみましょう。これによりLettering.jsによる文字を動かす為のラッピング作業も整い、また少しじらすことによって、「これから何が起こるのか?」と見ている人の期待感も高められると言う効果があります。

実際何をするかと言うと、1秒待ってからhtml要素にクラス名を適用させます。

setTimeout(function() {$('html').addClass("step-one");}, 1000);
   

このクラス名「step-one」は事前にセットしたマージンを上書きするために使用します。マージンを上書きしゼロにリセットすると、文字も本来のポジションに戻ります。

.step-one #poster h1 span { margin: 0; }
   

デモ内の小さい文字の方も同様にLettering.jsでspanタグを付け、CSSのtransitionやクラス名に対する時差を適用させています。唯一異なるのは背景画像を透過させていない点です。ただの白い文字なので、position: relativeを使用することが出来ます。

白い文字の方もスタート位置をランダム設定し、文字をオリジナルの位置にけり戻す為のクラス名を「step-two」としてもう少し遅いアニメーション開始時間を設定します。

$("#poster p span").each(function() {
   $(this).css({
      top: -(Math.floor(Math.random()*1001)+1500),
      left: Math.floor(Math.random()*1001)-500,
   });
});

setTimeout(function() {$('html').addClass("step-two");}, 3000);
   

ここではインラインスタイリングされたCSSの値にjQueryを適用させている為、!importantルールを使用する必要があります。!importantで値を上書きさせる為です。

.step-two #poster p span {
  top: 0 !important;
  left: 0 !important;
}
   

要約

もしご興味があれば・・・ですが、ここで使用しているフォントはNewcomenと言うフォントでTypekitから入手が可能です。
マージンは左右方向しかコントロール出来ないはずなのに、実際のアニメーションで上下にも動いているのは、親要素のtop paddingのアニメーションのお陰です。
あ、あと、本当にRed Sonjaがリメイクされるかどうかは知りません。ただの噂みたいですけれどね・・・。