Live study #3

cssだけでスライドショー(その2)

概要 cssだけで作るスライドショーを題材に、css3の animationとtransitionを学習。前回はこちら

凡例

前回のおさらい

前回は、お手本のPure CSS3 Cycle Sliderを参考に、以下の状態まで行いました。

html
css
.slide ul{
	list-style:none;
}
.slide ul li{
	float:left;
	width:100px;
	height:50px;
	position:relative;
	overflow:hidden;
}
.slide ul li h2{
	position:absolute;
	padding:0.5em 1em;
	background:rgba(0,0,0,0.5);
	color:#fff;
	top:0;
	left:-110%; /* %指定に変更しました */
}
.slide ul li:hover h2 {
	left:0;
}
.slide.transit ul li h2{
	-moz-transition:0.5s;
	-webkit-transition:0.5s;
	transition:0.5s;
	opacity:0;
}
.slide.transit:hover ul li h2 {
	left:0px;
	opacity:1;
}

引き続き、以下の通り進めます。

  1. 各<li>にCSS3のanimationを設定する
  2. 各<li>にhoverしたらanimationを一時停止させるanimation-play-stateを追加する
  3. div.progress-barにもanimationを設定する
  4. 表示させるエリアだけを見せて、他を隠す

各<li>にCSS3のanimationを設定する

transitionとanimationは似ていますが、いくつかの点で大きく異なります。整理してみましょう。

CSS3のtransitionとanimationの違い
注目ポイントtransitionanimation
再生秒数の設定transition-durationanimation-duration(CSSのショートハンドで指定する場合は先に書かれた秒数)。デフォルトは0秒なので何らかの時間を指定することになる。
開始時間を遅らせるtransition-delayanimation-delay(ショートハンドで指定する場合は後に書かれた秒数)
イージングの使用transition-timing-functionanimation-timing-function
変化させるcssプロパティの選択transition-propertyキーフレームの中で指定する。
キーフレームの使用できないanimation-nameで指定する。必須。
繰り返しの回数の指定できないanimation-iteration-count(0以上の整数か、infiniteで永久にループを指定できる)
繰り返しの方向指定できないanimation-direction(normalで毎回0→100%で動く。alternateで、偶数回は100→0%へと逆方向に動く。)
一時停止できないanimation-play-state(runningで動く。pausedで一時停止)
アニメーションの実行前や実行後のスタイル指定できないanimation-fill-mode(none , forwards , backwards , both が指定可能。)

スライドショーの場合は、ループさせ続ける必要があるので、animationを使用する訳です。div#sampleAnimeをanimationさせてみましょう。

この要素がdiv#sampleAnimeです。

CSS3のanimationの指定は以下の様に行います。

  1. 動かしたい要素のセレクターにanimationプロパティを指定します。ショートハンドで書くと「キーフレーム名 アニメーションにかかる時間 イージング 遅延時間 繰り返しの回数 再生方向」となります。「キーフレーム名」は必須ですし、再生秒数も書かないと0秒になるので指定します。div#sampleAnimeの設定は以下の通りです(分かり易くする為に、繰り返しの回数をinfiniteにしました)。
    				#sampleAnime {
    					/* この記事を書いている時点ではベンダープレフィックスが必要 */
    					-moz-animation:hogehoge 5s infinite;
    					-webkit-animation:hogehoge 5s infinite;
    					animation:hogehoge 5s infinite;
    				}
    			
  2. キーフレームの書式は以下の通り。一つのkeyframesの中カッコの中に、各タイミングを現す n% をセレクタにした中カッコが入れ子になる構造です。
    			@keyframes hogehoge {     /*@keyframes + 半角スペース + キーフレーム名 として中カッコを開ける*/
    				0% {                  /*開始時の状態を0%で指定して中カッコを開ける*/
    					margin-left: 10px; /*そのタイミングのcssを指定*/
    					background-color: #f00; /*複数指定できる。書き方は通常のcssと同じ*/
    				}                     /*中カッコを閉じる*/
    
    				20% {                 /*任意のタイミングを%で指定して中カッコを開ける*/
    					margin-left: 50px; /*そのタイミングのcssを指定*/
    				}                     /*中カッコを閉じる*/
    
    				100% {                /*終了時の状態は100%で指定。*/
    					margin-left: 50px;
    					background-color: #ff0;
    				}
    			}                         /*@keyframesの中カッコを閉じる*/
    			
    @keyframesで、注意すべき事が3つあります。
    • 各タイミングで指定しなかったプロパティは、変化が継続します。div#sampleAnimeでは、margin-leftは0→20%で10pxから100pxへとアニメーションし、20%→100%では変化しません。20%の時にbackground-colorを書いていないので、background-colorは0→100%にかけて色が変化します。
    • この記事を書いている時点では、@keyframesにもベンダープレフィックスをつけたものを用意する必要があります。@-moz-keyframes hogehoge{}、@keyframes hogehoge{}、@keyframes hogehoge{}を用意すれば良いでしょう。animation-nameは同じで大丈夫です。
    • この記事を書いている時点では、linear-gradientをanimationすることはできません。また、:afterや:beforeで作った疑似要素はFirefoxならanimationできますが、SafariやChromeではanimationできません。

スライドショーの@keyframes

各スライドの共通の動作は以下の順で行うことにします。

  1. 右からフレームイン
  2. ちょっと止まる
  3. 左へフレームアウト

お手本の@keyframesでは、各スライド毎に別のルールを設定していますが、工夫すれば1つの@keyframesで実装できます。

動作が分かりやすい様に、完成時に表示したいエリアのdiv.maskを追加して、赤いボーダーをつけた状態でアニメーションを表示してみます。

css
/*ベンダープレフィックスは省略しています。*/
.anime.loop .mask li {
	position:absolute;
	top:0;
	left:100%; /*フレーム「イン」させたいので、left:100%で右側の外に待機*/
	animation:slide 12s 0s infinite;	/*まず、各スライドに同じ@keyframesで動く様に指示*/
	animation-play-state:running;		/*webkitの動作が怪しいので追加。*/
}
.anime.loop .mask li:nth-of-type(1) {
	animation-delay:0s;/* 1番目のスライドはすぐにスタート */
}
.anime.loop .mask li:nth-of-type(2) {
	animation-delay:4s;/* 2番目のスライドは4秒後にスタート */
}
.anime.loop .mask li:nth-of-type(3) {
	animation-delay:8s;/* 3番目のスライドは8秒後にスタート */
}
/*以下が@keyframes*/
@keyframes slide {
	0% {left:100%;opacity:0.5;z-index:10;}	/*フレームイン開始*/
	10% {left:0%;opacity:1;}				/*(a)全体の1/10秒でフレームイン終了*/
	33.3% {left:0%;opacity:1;z-index:-10;}	/*(b)ここまで停止して、フレームアウト開始(b = 100 / スライド数) */
	43.3% {left:-100%;top:0%;opacity:0.5;}	/*(c)フレームアウト終了(c = a) */
	50% {left:-100%;top:100%;}				/* 分かりやすい様に、見えないエリアで迂回させています */
	70% {left:100%;top:100%;}
	80% {left:100%;top:0%;}
}
  1. まず、各スライドに同じ@keyframesで動く様に指定
  2. その後で遅延時間のanimation-delayだけを個別に変更

一つの@keyframesと、スライド毎のdelayで、全てのスライドの動きを処理しているのが、この設定のミソです。

-moz-と-webkit-のベンダープレフィックス付き@keyframesを用意しても3つで済みます。

以下の計算式で任意のスライド枚数のanimation-delayを求めることができます。

n番目に出現するスライドのanimation-delayの計算式

x = S N ⁢ * (n⁢-⁢1)

  • S(秒) = animation-duration
  • N(個)= スライドの総数(2以上の自然数)
  • n(番目)= スライドの出現順
  • x(秒)= n番目に出現するスライドのanimation-delay

12秒で3個のスライドをループさせる場合の各スライドのanimation-delay

  • 1つ目: 0 = 12 3 ⁢ * (1⁢-⁢1)
  • 2つ目: 4 = 12 3 ⁢ * (2⁢-⁢1)
  • 3つ目: 8 = 12 3 ⁢ * (3⁢-⁢1)

hoverしたらanimationを一時停止させる

animation-play-stateを各<li>のhoverに設定すると、そのスライドのアニメは止まりますが、他のスライドは動き続けます。

css
/*SAMPLE LI:hover*/
/*これではアニメーションがずれてしまう...*/
.anime.loop.sample6 .mask li:hover{
	animation-play-state:paused;
}

これでは、hoverの後でアニメがずれてしまうので、どのスライドにhoverしても、全てのアニメーションが止まる様にしなければなりません。そこで、セレクターにちょっとした工夫をします。SAMPLE LI:hoverと以下のSAMPPLE MASK:hoverにマウスをのせて、動作を比較しましょう。

css
/*SAMPLE MASK:hoverの工夫*/
/*セレクターを「liの親のhoverの子のli」にするのがポイント*/
.anime.loop.paused .mask:hover li{
	animation-play-state:paused;
}

div.progress-barにもanimationを設定する

css
.progress .progress-bar {
	background:rgba(0,0,0,1);
	height:5px;
	width:100%;
	position:absolute;
	z-index:100;
	bottom:0;
	left:0;
	-moz-animation:bar 12s linear infinite;
	-webkit-animation:bar 12s linear infinite;
	animation:bar 12s linear infinite;
}
@keyframes bar {
	0%,43.3%,76.6% {width:0;opacity:0;}			/*スライドのフレームイン中は表示しない */
	10%,53.3%,86.6% {width:10%;opacity:0.5;}	/*フレームイン終了。ここからbarがのびる */
	30%,63.3%,96.6% {opacity:1;}				/*barがのびきる前にopacityを1にするとおしゃれ */
	33.3%,66.6%,99.9% {width:100%;opacity:0.1;}	/*ここまではbarがのびる */
	34%,67%,100% {width:100%;opacity:0;}		/*barを消す */
}
.progress .mask:hover .progress-bar{
	animation-play-state:paused;
	bottom:-10px;
}

.progress-bar の@keyframesでは、お手本の@keyframesに習って、keyframeの%を、列挙する形でセレクタ指定してみました。スマートなやり方ですね。

また、hover時に、.progress-barもスライドと同様に一時停止しておきます。

表示させるエリアだけを見せて、他を隠す

html
css

#complete .mask {
	margin:0 auto;
	border:2px solid red;
	position:relative;
	cursor:pointer;
	overflow:hidden;
}
#complete ul{
	list-style:none;
	height:50px;
	width:100px;
	margin: 0;
	padding: 0;
	position:relative;
}
#complete li {
	margin:0;
	padding: 0;
	height:50px;
	width:100px;
	top:0;
	left:100%;
	position:absolute;
	overflow:hidden;
	-moz-animation:slide 12s 0s infinite;
	-webkit-animation:slide 12s 0s infinite;
	animation:slide 12s 0s infinite;
	-moz-animation-play-state:running;
	-webkit-animation-play-state:running;
	animation-play-state:running;
}
#complete li:nth-of-type(1) {
	-moz-animation-delay:0s;
	-webkit-animation-delay:0s;
	animation-delay:0s;
}
#complete li:nth-of-type(2) {
	-moz-animation-delay:4s;
	-webkit-animation-delay:4s;
	animation-delay:4s;
}
#complete li:nth-of-type(3) {
	-moz-animation-delay:8s;
	-webkit-animation-delay:8s;
	animation-delay:8s;
}
#complete a {
	height:50px;
	width:100px;
	display:block;
}
#complete h2 {
	position:absolute;
	padding:0.5em 1em;
	background:rgba(0,0,0,0.5);
	color:#fff;
	top:0;
	left:-110%;
	opacity:0;
	-moz-transition:0.5s;
	-webkit-transition:0.5s;
	transition:0.5s;
}
#complete .mask:hover h2 {
	left:0;
	opacity:1;
}

#complete .mask:hover .progress-bar,
#complete .mask:hover li{
	-moz-animation-play-state:paused;
	-webkit-animation-play-state:paused;
	animation-play-state:paused;
}
#complete .progress-bar {
	background:rgba(0,0,0,1);
	height:5px;
	width:100%;
	position:absolute;
	z-index:100;
	bottom:0;
	left:0;
	-moz-animation:bar 12s linear infinite;
	-webkit-animation:bar 12s linear infinite;
	animation:bar 12s linear infinite;
}
/* keyframes for slide */
@-moz-keyframes slide {
	0% {left:100%;opacity:0.5;z-index:10;}	/*フレームイン開始*/
	10% {left:0%;opacity:1;}				/*(a)全体の1/10秒でフレームイン終了*/
	33.3% {left:0%;opacity:1;z-index:-10;}	/*(b)ここまで停止して、フレームアウト開始(b = 100 / スライド数) */
	43.3% {left:-100%;top:0%;opacity:0.5;}	/*(c)フレームアウト終了(c = a) */
	50% {left:-100%;top:100%;}				/* 分かりやすい様に、見えないエリアで迂回させた */
	70% {left:100%;top:100%;}
	80% {left:100%;top:0%;}
}
@-webkit-keyframes slide {
	0% {left:100%;opacity:0.5;z-index:10;}	/*フレームイン開始*/
	10% {left:0%;opacity:1;}				/*(a)全体の1/10秒でフレームイン終了*/
	33.3% {left:0%;opacity:1;z-index:-10;}	/*(b)ここまで停止して、フレームアウト開始(b = 100 / スライド数) */
	43.3% {left:-100%;top:0%;opacity:0.5;}	/*(c)フレームアウト終了(c = a) */
	50% {left:-100%;top:100%;}				/* 分かりやすい様に、見えないエリアで迂回させた */
	70% {left:100%;top:100%;}
	80% {left:100%;top:0%;}
}
@keyframes slide {
	0% {left:100%;opacity:0.5;z-index:10;}	/*フレームイン開始*/
	10% {left:0%;opacity:1;}				/*(a)全体の1/10秒でフレームイン終了*/
	33.3% {left:0%;opacity:1;z-index:-10;}	/*(b)ここまで停止して、フレームアウト開始(b = 100 / スライド数) */
	43.3% {left:-100%;top:0%;opacity:0.5;}	/*(c)フレームアウト終了(c = a) */
	50% {left:-100%;top:100%;}				/* 分かりやすい様に、見えないエリアで迂回させた */
	70% {left:100%;top:100%;}
	80% {left:100%;top:0%;}
}
/* keyframes for progress-bar */
@-moz-keyframes bar {
	0%,43.3%,76.6% {width:0;opacity:0;}
	10%,53.3%,86.6% {width:10%;opacity:0.5;}
	30%,63.3%,96.6% {opacity:1;}
	33.3%,66.6%,99.9% {width:100%;opacity:0.1;}
	34%,67%,100% {width:100%;opacity:0;}
}
@-webkit-keyframes bar {
	0%,43.3%,76.6% {width:0;opacity:0;}
	10%,53.3%,86.6% {width:10%;opacity:0.5;}
	30%,63.3%,96.6% {opacity:1;}
	33.3%,66.6%,99.9% {width:100%;opacity:0.1;}
	34%,67%,100% {width:100%;opacity:0;}
}
@keyframes bar {
	0%,43.3%,76.6% {width:0;opacity:0;}			/*スライドのフレームイン中は表示しない */
	10%,53.3%,86.6% {width:10%;opacity:0.5;}	/*フレームイン終了。ここからbarがのびる */
	30%,63.3%,96.6% {opacity:1;}				/*barがのびきる前にopacityを1にするとおしゃれ */
	33.3%,66.6%,99.9% {width:100%;opacity:0.1;}	/*ここまではbarがのびる */
	34%,67%,100% {width:100%;opacity:0;}		/*barを消す */
}

仕上げに、.maskのoverflowをhiddenして完成です。

ここまで説明の為にclassを追加しながらcssを足し込んでいて、ちょっと判りづらい所もあったので、id=complete として整理し直したhtmlとcssにしました。ベンダープレフィックスも書いてあります。

まとめ

ちょっと疲れました

思った以上にボリュームのある内容になりました。しかし、ベンダープレフィックスがある為に記述量が増えてしまいがちな@keyframesについて、スライド個別に作成しないで良い事に気付けたのは収穫でした。

スライドショーの使い道

Web表現としては手垢がついた感もあるスライドショーですが、TOPページでお為ごかしに使っているだけでは勿体ないです。

画面上で動いている物に目がいくのは人間のなので、注目を引く効果があるのはもちろんです。が、それだけではありません。

スライドショーは、ほんの少しのアイデアと工夫で、様々なバリエーションへ発展できる表現です。例えば...

仕上げの細部にこだわろう

動きの細部(スピード・イージング・フェード)の演出しだいで、がらりと印象が変わるのもスライドショーの面白さです。どんな演出がしたいのか、よく考えましょう。

CSSスライドショーはスマートフォンに最適!(かな?)

スマートフォンやタブレット端末のブラウザは、CSS3に対応している前提で作成できるので、こうしたCSSでの演出に向いていると言えます。Flash非対応のデバイスだからjQueryで!と短絡する前に、CSSでも出来るようにしておく事で、選択肢が広がります。

興味とチャレンジ精神のある人は、是非、自分でCSSスライドショーを作ってみて下さい。3パターンくらいを作り終える頃には、css animationを自在に操れるようになるはずです。