動くCSSのためのメモ。
なんだかCSSでできる事がどんどん増えてきましたね。以前はJavaScriptを使って実装していた動くコンテンツも、CSSだけで表現されてるのをよく見ます。そんなわけで、ここいらで、CSSで動かすエフェクトについて、まとめてみたいと思います:)。
※この記事を書いてる時点の最新ブラウザは以下の通り。また、記事の内容は、PCでの閲覧を想定してます。
- Microsoft Internet Explorer 11.0
- Mozilla Firefox 28.0
- Google Chrome 34.0
- Apple Safari 7.0
マウスオーバー(ホバー)エフェクト
ボタンや画像にカーソルを乗せた時の反応って大事ですよね。
リンクするエリアにカーソルを合わせた時に、カーソルが指のアイコンに変わったり、テキストの色が変わったりすれば、カーソルが乗ったという事が認識しやすくなります:)。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - マウスオーバーエフェクト</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <p class="txt">こちらは<a href="">テキストリンク</a>です。</p> </div> </body> </html>
body { background: url(../img/bg.png); font-family: "Heiti SC"; } a { color: lightSeaGreen; } a:hover { color: indianRed; text-decoration: none; } .txt { margin: 50px 0 0; text-align: center; }
:hover
を使ってスタイルを指定しておけば、カーソルが乗った時には、そのスタイルが適用されます。
けどそれだけだと、カチッと切り替わるだけ。
フェードでふわっと切り替わる
サイトの雰囲気にもよるけれど、もちょっとだけ柔らかい印象にしたいなって時には、ふわっとするとよいかもです。文字の色が切り替わるスピードと、下線が消えてくスピードを調整することで、ふわっとした感じになります:)。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - フェードでふわっと切り替わる</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <p class="txt">こちらは<a href="">ふわっとリンク</a>です。</p> </div> </body> </html>
/* 略 */ .txt a { border-bottom: 1px solid rgba(32,178,170,1); text-decoration: none; transition: border-color 0.3s, color 0.3s; } .txt a:hover { border-color: rgba(205,92,92,0); }
切り替わるスピードを調整するにはtransitionプロパティを使います!
下記のように書くと、a要素でのcolorプロパティの値の変化の仕方を指定することができます。下記は「0.3秒かけていい感じで切り替わる」という指定。
a {
transition: color 0.3s ease 0s;
}
transition
の値は左から順に、property、duration、timing-function、delayを表してて、上の例を個別に指定するなら、下記のようにも書けます。
a {
transition-property: color;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s;
}
初期値を省略して、下記だけでもよいです:)。
.txt a {
transition: color 0.3s;
}
transition
の4つのプロパティは、それぞれ以下の役割と、初期値を持ってます。
transition-property
- 効果を適用したいプロパティ名を指定します。初期値は「
all
」すべて※のプロパティに適用します。※
transition
を適用できるプロパティは、プロパティの値を数値で表現できるものすべて。color
の値に使われるred
やlightSeaGreen
などの色名も、RGBなどの数値で表すことができるのでちゃんと適用されます。 transition-duration
- 変化の開始から完了までにかかる時間を、秒数で指定します。初期値は「
0s
」カチッと切り替わります。
1秒(1000ミリ秒) =1s
(1000ms
)。 transition-timing-function
- 変化の仕方(イージング)を指定します。初期値は「
ease
」ゆっくり始まってゆっくり終わる、一番いい感じのイージングです。
他にlinear
、ease-in
、ease-out
、ease-in-out
が用意されてます。
cubic-bezier関数を使えばオリジナルなイージングを作ることもできます。詳しくはこちらの記事を参照のこと。 transition-delay
- 変化を開始するまでの待ち時間を、秒数で指定します。初期値は「
0s
」すぐに変化を開始します。
マイナスの値を指定すると、その分進んだ時点から変化を開始します。詳しくは後述。
下線も同じようにtext-decoration-color
をtransition
させたいところですが、text-decoration-colorプロパティはまだ対応ブラウザが少ないみたいなので、下線はtext-decoration
じゃなくてborder-bottom
で表示することにしました(2014年4月現在)。
border-color
を、カーソルが乗る前は「rgba(32,178,170,1)
(みどり)」、カーソルが乗った時は「rgba(105,92,92,0)
(あかい透明)」となるように指定しました。
文字色と下線の色、ひとつの要素内で複数のプロパティをtransitionさせるには、transition
の値を、プロパティごとに「,(カンマ)」区切りで続けて書きます。ここでは、前述のtransition
にborder-color
を追記しました。
.txt a {
border-bottom: 1px solid rgba(32,178,170,1);
text-decoration: none;
transition: color 0.3s, border-color 0.3s;
}
.txt a:hover {
border-color: rgba(105,92,92,0);
}
#20b2aa
という16進数の値から、rgba(32,178,170,1)
みたいなRGB値に変換するのには下記ページを利用しましたよ;D。
画像ボタンもふわっとする
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 画像ボタンもふわっとする</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <p class="bnr"><a><img src="http://placehold.it/300x100/20b2aa/ffffff&text=banner"></a></p> </div> </body> </html>
.bnr a { display: inline-block; background: url(http://placehold.it/300x100/cd5c5c/ffffff&text=banana) no-repeat; background-size: cover; } .bnr a img { vertical-align: middle; transition: opacity 0.3s; } .bnr a:hover img { opacity: 0; }
ふわっとカチッする
CSSで作ったボタンなら、background-color
やbox-shadow
など、いじれるプロパティがいっぱいあるので、ふわっとさせ甲斐がありますねー!まとめてtransition
を指定すれば、より魅力的な変化を表現できます。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - ふわっとカチッする</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <p class="btn"><a>ボタンでございます</a></p> </div> </body> </html>
.btn a { display: block; cursor: pointer; width: 300px; margin: 0 auto; padding: 20px; color: #fff; text-align: center; text-decoration: none; background-color: #20b2aa; border-radius: 5px; box-shadow: 0 6px 0 #047c71, 0 12px 0 rgba(0,0,0,0.2); -webkit-transition: color 0.3s, background-color 0.3s, box-shadow 0.3s, -webkit-transform 0.3s; transition: color 0.3s, background-color 0.3s, box-shadow 0.3s, transform 0.3s; } .btn a:hover { background-color: #3cc4bd; box-shadow: 0 3px 0 #12978d, 0 6px 0px rgba(0,0,0,0.2); -webkit-transform: translateY(3px); transform: translateY(3px); } .btn a:active { color: #ddd; background-color: #12978d; box-shadow: 0 0 0 #047c71, 0 0 0px rgba(0,0,0,0.2); -webkit-transform: translateY(6px); transform: translateY(6px); transition-duration: 0.1s; }
また、カーソルを乗せた時にはゆったり動いてますが、マウスを押下した時にはちょっと早めに動くようにしてます。ここでは、duration
の値を、下記のように変えています。
.btn a {
/* 略 */
transition: color 0.3s, background-color 0.3s, box-shadow 0.3s, transform 0.3s;
-webkit-transition: color 0.3s, background-color 0.3s, box-shadow 0.3s, -webkit-transform 0.3s;
}
.btn a:active {
transition-duration: 0.1s;
}
<a>
に対して指定したtransition
の値を、active時にtransition-duration
の値のみ上書きしてるんですねー。これだけで、マウスを押下した時は0.1秒で変化して、それ以外のときは0.3秒で変化するようになります。
発光する
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 発光するボタン</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <p class="btn"><a>発光するボタンでございます</a></p> </div> </body> </html>
/* 略 */ .btn a:hover { background-color: #96e9e6; box-shadow: 0 3px 0 #12978d, 0 6px 0px rgba(0,0,0,0.2); -webkit-transform: translateY(3px); transform: translateY(3px); } .btn a:active { color: #ddd; background-color: #12978d; box-shadow: 0 0 0 #047c71, 0 0 0px rgba(0,0,0,0.2); -webkit-transform: translateY(6px); transform: translateY(6px); transition-duration: 0.1s; }
こんな時にはanimation
というプロパティが使えます。ピカッと感が出ましたね!
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 発光するボタン</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <p class="btn"><a>発光するボタンでございます</a></p> </div> </body> </html>
/* 略 */ .btn a:hover { background-color: #20b2aa; box-shadow: 0 3px 0 #12978d, 0 6px 0px rgba(0,0,0,0.2); -webkit-transform: translateY(3px); transform: translateY(3px); -webkit-animation: flash 1s; animation: flash 1s; } .btn a:active { color: #ddd; background-color: #12978d; box-shadow: 0 0 0 #047c71, 0 0 0px rgba(0,0,0,0.2); -webkit-transform: translateY(6px); transform: translateY(6px); transition-duration: 0.1s; } @-webkit-keyframes flash { 0% { background-color: #20b2aa; } 10% { background-color: #96e9e6; } 100% { background-color: #20b2aa; } } @keyframes flash { 0% { background-color: #20b2aa; } 10% { background-color: #96e9e6; } 100% { background-color: #20b2aa; } }
animationプロパティ
まずは1〜4行めのanimationプロパティについて。
.flash a:hover {
background-color: #20b2aa;
animation: flash 1s;
-webkit-animation: flash 1s;
}
animationプロパティにはname、duration、timing-function、delay、iteration-count、direction、play-state、fill-modeの8つの値が指定できます。durationとtiming-functionとdelayはtransition
にもありましたね。
それぞれ、以下の役割と初期値を持ってます。
animation-name
- 適用したいアニメーション名を指定します。初期値は「
none
」何も指定されてません。
詳しくは@keyframesルールの項を参照。 animation-duration
- アニメーションの一回分の長さを、秒数で指定します。初期値は「
0s
」アニメーションしません。 animation-timing-function
- アニメーションの仕方(イージング)を指定します。初期値は「
ease
」(transition
と同様)。 animation-delay
- アニメーションを開始するまでの待ち時間を、秒数で指定します。初期値は「
0s
」すぐにアニメーションを開始します。
マイナスの値を指定すると、その分進んだ時点からアニメーションを開始します(transition
と同様)。 animation-iteration-count
- アニメーションを繰り返す回数を指定します。初期値は「
1
」1回だけ再生します。
「infinite
(無限)」という指定もできます。 animation-direction
animation-iteration-count
で2回以上に指定した場合に、アニメーションを折り返すか、始めに戻すかを指定します。初期値は「normal
」同じアニメーションを繰り返します。
「alternate
」とすると、偶数回めのアニメーションが逆再生します。
「reverse
」とすると、逆再生が繰り返され、「alternate-reverse
」とすると、奇数回めのアニメーションが逆再生になります。animation-play-state
- アニメーションを再生させたり一時停止させたりできます。初期値は「
running
」再生する状態です。
「paused
」と指定すると、一時停止の状態になります。 animation-fill-mode
- アニメーションする前と後に、適用するスタイルを指定します。初期値は「
none
」アニメーションしてるとき以外に、スタイルは適用されません。詳しくは後述。
animationプロパティにまとめて指定する場合は、半角スペースを空けて、下記みたく連ねて書くこともできます:)。
p {
animation: name ease-in-out 2s 1s 5 alternate running forwards;
}
順番は自由だけれど、ひとつだけ、duration
とdelay
の順番だけは「duration
が先」と決まってるので注意です。
上記の場合なら、1秒待ってから2秒かけてアニメーションすることになります。
@keyframesルール
「アニメーション」は、別途@keyframesルールという、キーフレームを定義するための特別な構文を使って用意します。ここで定義したアニメーション名が、animation-name
で指定する値として使えるって寸法です。
@keyframes flash {
0% { background-color: #20b2aa; }
10% { background-color: #96e9e6; }
100% { background-color: #20b2aa; }
}
@-webkit-keyframes flash {
0% { background-color: #20b2aa; }
10% { background-color: #96e9e6; }
100% { background-color: #20b2aa; }
}
※@keyframes
に付くベンダープレフィックスは、「頭」じゃなくて、「@」の後なのでご注意。
アニメーションの前後に適用されるスタイル(animation-fill-mode
)について
初期値(none
)の状態だと、アニメーション完了後には、もともとその要素に指定していたスタイルが適用されます。
下のサンプルでは、background-color
に赤色が指定してあるp要素に、カーソルを乗せると1秒かけて緑色にグラデーションするgradation
というアニメーションを適用しています。
p {
background-color: lightSeaGreen;
}
p:hover {
animation: gradation 1s;
}
@keyframes gradation {
0% { background-color: lightSeaGreen; }
100% { background-color: indianRed; }
}
カーソルを乗せてみると、アニメーションが終わった瞬間、赤色に戻っちゃいました…!
これを回避するには、下記のように:hover
に別途、完了後のスタイルを指定すればよいです。
p:hover {
background-color: indianRed;
animation: gradation 1s;
}
けれど、animation-delay
でアニメーションの開始を遅らせた場合、まず:hover
で指定したスタイルが適用されてから、アニメーションが開始するため、変なんなっちゃいます…。
p:hover {
background-color: indianRed;
animation: gradation 1s .5s;
}
そんな時に使えるのがanimation-fill-modeプロパティ;D!
値に「backwards
」と指定すれば、animation-delay
でアニメーションが始まるまで待ってる間も、アニメーション開始時のスタイルを優先して適用してくれます。
p:hover {
background-color: indianRed;
animation: gradation 1s .5s;
animation-fill-mode: backwards;
}
「forwards
」はその逆で、アニメーション完了時のスタイルが、アニメーション完了後も適用され続けます。
この指定をすれば:hover
に、別途、完了後のスタイルを指定する必要がなくなりますね:D。
p:hover {
animation: gradation 1s .5s;
animation-fill-mode: forwards;
}
「both
」はその両方。@keyframes
で指定したスタイルが優先して適用されるようになります。
下のサンプルでは、p要素のbackground-color
をグレーに指定してますが、カーソルを乗せた時には、緑色から赤色へのグラデーションが再生されます。
p {
background-color: indianRed;
}
p:hover {
animation: gradation 1s .5s;
animation-fill-mode: both;
}
animation-fill-mode
の値の役割をまとめてみると下図みたいな感じです!
使いどころに合わせて、効率的に使いたいですねー;)。
詳細はあとから表示する
最初は表示されてないんだけど、サムネイル画像の上にカーソルを乗せると、その画像に関する情報が表示されるような、そんなUIよくありますね。
ごちゃごちゃした情報は見たい時だけ、最初の見た目が煩雑にならずにシンプルなデザインにできるので、フラットなデザインとも相性がいいんですよね:)。
下のサンプルみたいなの、よく見る気がします:D。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 詳細はあとから表示する</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <ul> <li class="type1"> <img src="http://placehold.it/200x180/20b2aa/ffffff&text=image"> <dl> <dt>Placehold.it</dt> <dd>この画像は「Placehold.it」で生成されるダミー画像を使用しています。</dd> <dd><a href="http://www.placehold.it/" target="_blank">Placehold.it</a></dd> </dl> </li> <li class="type2"> <img src="http://placehold.it/200x180/20b2aa/ffffff&text=image"> <dl> <dt>Placehold.it</dt> <dd>「http://placehold.it/[SIZE]/[BGCOLOR]/[TEXTCOLOR]&text=[DUMMYTEXT]」というようなURLで、任意のダミー画像を生成してくれてとっても便利。</dd> <dd><a href="http://www.placehold.it/" target="_blank">Placehold.it</a></dd> </dl> </li> <li class="type3"> <img src="http://placehold.it/200x180/20b2aa/ffffff&text=image"> <dl> <dt>Placehold.it</dt> <dd>このダミー画像の場合は「http://placehold.it/200x180/20b2aa/ffffff&text=image」という具合。</dd> <dd><a href="http://www.placehold.it/" target="_blank">Placehold.it</a></dd> </dl> </li> </ul> </div> </body> </html>
body { background: url(../img/bg.png); font-family: "Heiti SC"; } a { color: lightSeaGreen; } a:hover { color: indianRed; text-decoration: none; } ul { list-style: none; top: 0; height: 180px; margin: 0; padding: 0; text-align: center; } ul li, ul li dl { width: 200px; height: 180px; } ul { letter-spacing: -1em; } ul li { display: inline-block; position: relative; overflow: hidden; margin: 0 5px; letter-spacing: 0; } ul dl { box-sizing: border-box; -moz-box-sizing: border-box; position: absolute; top: 0; margin: 0; padding: 20px 25px; color: #fff; background: rgba(205,92,92,.9); } ul dl dt { margin-bottom: 0.3em; } ul dl dd { margin: 0; font-size: 10px; line-height: 1.6; text-align: justify; word-break: break-all; } ul dl dd:last-of-type { margin-top: 10px; text-align: right; } ul a { padding: 0.3em 0.5em; background-color: #fff; } /* type1 */ .type1 dl { opacity: 0; -webkit-transform: translateY(100%); transform: translateY(100%); -webkit-transition: opacity 0.6s, -webkit-transform 0.6s; transition: opacity 0.6s, transform 0.6s; } .type1:hover dl { opacity: 1; -webkit-transform: translateY(0); transform: translateY(0); } /* type2 */ .type2 { overflow: visible; -webkit-perspective: 1000px; perspective: 1000px; } .type2 img, .type2 dl { -webkit-transition: opacity 0.6s, -webkit-transform 0.6s; transition: opacity 0.6s, transform 0.6s; -webkit-backface-visibility: hidden; backface-visibility: hidden; } .type2:hover img { -webkit-transform: rotateX(180deg); transform: rotateX(180deg); } .type2 dl { background-color: #cd5c5c; -webkit-transform: rotateX(-180deg); transform: rotateX(-180deg); } .type2:hover dl { -webkit-transform: rotateX(0); transform: rotateX(0); } /* type3 */ .type3 dl { background-color: transparent; } .type3 dl dt, .type3 dl dd { position: relative; z-index: 1; opacity: 0; transition: opacity 0.3s; } .type3:hover dl dt, .type3:hover dl dd { opacity: 1; transition-delay: 0.3s; } .type3 dl::before, .type3 dl::after { content: ""; display: block; position: absolute; top: 0; left: 0; width: 100px; height: 180px; background: #cd5c5c; opacity: 0; -webkit-transition: opacity 0.6s, -webkit-transform 0.6s; transition: opacity 0.6s, transform 0.6s; } .type3:hover dl::before, .type3:hover dl::after { opacity: 0.9; transition-duration: 0.3s; } .type3 dl::before { -webkit-transform: translateX(-175px) skew(-30deg); transform: translateX(-175px) skew(-30deg); } .type3 dl::after { -webkit-transform: translateX(275px) skew(-30deg); transform: translateX(275px) skew(-30deg); } .type3:hover dl::before { -webkit-transform: translateX(0) skew(0); transform: translateX(0) skew(0); } .type3:hover dl::after { -webkit-transform: translateX(100px) skew(0); transform: translateX(100px) skew(0); }
そんなわけで、左から順に仕組みメモです。
サムネイル画像部分のHTMLはそれぞれ下記のようになってます。
<ul class="details">
<li>
<img src="http://placehold.it/200x180/20b2aa/ffffff&text=image">
<dl>
<dt>Placehold.it</dt>
<dd>この画像は「Placehold.it」で生成されるダミー画像を使用しています。</dd>
<dd><a href="http://www.placehold.it/" target="_blank">Placehold.it</a></dd>
</dl>
</li>
<!-- 略 -->
</ul>
<li>
の中に、img要素(サムネイル画像)と、dl要素(詳細情報)が並んでる状態ですね。
下からニュッと出る
詳しい情報は画像の下に隠しておいて、カーソルが乗ったら下からスッとスライドする仕組み。
まずはli要素にposition: relative
を指定。これで、li要素が、その小要素を絶対配置するときの基準になります。dl要素にposition: absolute
を指定しtop: 0
とすれば、img要素の上に重なった状態で配置されます。
dl要素の上下のスライドはtransformプロパティのtranslate
で移動させてます。
最初の状態では、dl要素にtranslateY(100%)
と指定。これで、その要素の高さ分、下方向に移動します。カーソルが乗ったときはtranslateY(0)
として、元の位置に戻します。
くるんと裏返る
まるで一枚のカードみたく、写真の裏面に詳細情報が載ってるような表現です。
上述と同じように、position: absolute
でimg要素とdl要素を重ねて配置。
最初の状態では、dl要素は裏返ってる状態なので、rotateX()
を使ってX軸を中心に上下に回転させておき、カーソルが乗った時に、img要素とdl要素を同時に+180°回転させてます。
.type2 dl {
background-color: #cd5c5c;
transform: rotateX(-180deg);
-webkit-transform: rotateX(-180deg);
}
.type2:hover img {
transform: rotateX(180deg);
-webkit-transform: rotateX(180deg);
}
.type2:hover dl {
transform: rotateX(0);
-webkit-transform: rotateX(0);
}
カーソルが乗った時に<img>
と<dl>
を、同じタイミングで回転させる事で、一枚のカードのように見せてるんですねー。
裏返る演出で大事なのがbackface-visibility
というプロパティ。このプロパティにhidden
と指定した要素は、裏返った時に不可視状態になります。
backface-visibility
で裏側だと判断されるのは、transformプロパティのrotateX()
かrotateY()
で、90°以上回転した時。下図は、左が「表面の要素のみ」真ん中が「裏面の要素のみ」になってます。表面が裏返ると不可視状態になり、その瞬間に裏面が可視状態になってるのがよくわかりますねー。
この指定がないと下図のように、裏側も丸見え、というか、裏面が表面の上に乗っちゃってます。
backface-visibility
について詳しくは下記サイトを参照のこと。
あと、回転する要素の親要素には、perspectiveプロパティを指定してます。
.hover .details .type2 {
perspective: 1000px;
-webkit-perspective: 1000px;
}
perspective
は、遠近感を指定することができるプロパティ。指定する値は、その要素を見ている視点の位置を表してて、ここでは、1000px離れた所で見てる感じになります。
つまり、この値が小さい(近い)ほど遠近感が強く、大きい(遠い)ほど遠近感が緩くなるってことですね:)。
この指定がないと、立体感がなくなって、裏返ったのか縦に縮んだのかわからなくなっちゃいます…。
perspective
については下記記事が詳しいです。
HTML5 × CSS3 × jQueryを真面目に勉強 – #10.1 CSS3 Transforms(3D) | Developers.IO(2012.12.27)
左右から背景が出てくる
パネル状の背景が左右から入ってきて、カーテンを閉めるように中央でピッタリ閉じられると、詳細情報がフェードインしてきます。
左右から出てくる背景は::before疑似要素と::after疑似要素で表示させてます。
疑似要素を使うと、指定した要素の中に、新たに要素を追加できちゃいます。
ただし、要素を追加するにはもうひとつ、contentプロパティというのも使わなきゃいけません。下記みたく書きます。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - ::beforeと::afterについて</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <p> / </p> </div> </body> </html>
p { margin: 50px 0 0; text-align: center; } p::before { content: "::beforeの疑似ですよ"; } p::after { content: "::afterの疑似ですよ"; }
HTMLには「 / 」と出力するだけのp要素がひとつ、なのにPREVIEWを見るとテキストが表示されてますね!
こんな感じで、疑似要素とcontentプロパティを使えば、HTMLで書かれた要素とは別に、CSSで新たに要素を作れちゃうんです(擬似的に!):D。
::before
は、指定した要素の開始タグの直後に、::after
は、指定した要素の閉じタグの直前に、要素を追加します。※Chromeとかで「要素の検証」をしてみても確認できますよ;)。
左右から出てくる背景は、dl要素内に、::before
と::after
で2つの要素を追加してたわけです(擬似的に!:D)。
他にももっといろんなプロパティと組み合わせればトリッキーな演出だってできちゃいます。
下記サイトでいろんなエフェクトが紹介されてます。どれも素敵ですねーXD!
Circle Hover Effects with CSS Transitions | Codrops(2012.8.8)
タブコンテンツ
タブボタンをクリックすることで、表示する内容を切り替えるタブコンテンツも、CSSだけでできちゃう時代です:)。
CSSで切り替えを行うためには、ちょっとした下ごしらえが必要なので、まずはその仕組みについてまとめてみます。
CSSで切り替える仕組み
そんなわけで、下の仕組みがよくわかるサンプルのソースコードを見ながら要点を解説です。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - CSSで切り替える仕組みがよく分かるサンプル</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" name="switch" id="tab-1" checked> <input type="radio" name="switch" id="tab-2"> <input type="radio" name="switch" id="tab-3"> <input type="radio" name="switch" id="tab-4"> <input type="radio" name="switch" id="tab-5"> <ul class="tabBtn"> <li><label for="tab-1">タブ1</label></li> <li><label for="tab-2">タブ2</label></li> <li><label for="tab-3">タブ3</label></li> <li><label for="tab-4">タブ4</label></li> <li><label for="tab-5">タブ5</label></li> </ul> <div class="tabContents"> <section>タブコンテンツ1</section> <section>タブコンテンツ2</section> <section>タブコンテンツ3</section> <section>タブコンテンツ4</section> <section>タブコンテンツ5</section> </div> </div> </body> </html>
#wrapper { box-sizing: border-box; -moz-box-sizing: border-box; } /* :::::: button :::::: */ .tabBtn { display: table; width: 100%; margin: 0 0 1px; padding: 0; } .tabBtn li { display: table-cell; width: 20%; border-right: 1px solid #fff; background-color: #20b2aa; text-align: center; vertical-align: middle; } .tabBtn li:last-child { border-right: 0; } .tabBtn li label { display: block; cursor: pointer; padding: 10px 0; color: #fff; transition: background-color .3s; } .tabBtn li label:hover { background-color: rgba(205,92,92,.5); } /* :::::: mechanism :::::: */ .tabContents section { opacity: 0.1; text-align: center; transition: opacity 0.3s; } #tab-1:checked ~ .tabBtn li [for="tab-1"], #tab-2:checked ~ .tabBtn li [for="tab-2"], #tab-3:checked ~ .tabBtn li [for="tab-3"], #tab-4:checked ~ .tabBtn li [for="tab-4"], #tab-5:checked ~ .tabBtn li [for="tab-5"] { background-color: #cd5c5c; } #tab-1:checked ~ .tabContents section:nth-child(1), #tab-2:checked ~ .tabContents section:nth-child(2), #tab-3:checked ~ .tabContents section:nth-child(3), #tab-4:checked ~ .tabContents section:nth-child(4), #tab-5:checked ~ .tabContents section:nth-child(5) { opacity: 1; background-color: #fff; }
HTML
まずはタブボタンと、それに付随するコンテンツを設置します。
<ul class="tabBtn">
<li><label for="tab-1">タブ1</label></li>
<li><label for="tab-2">タブ2</label></li>
<li><label for="tab-3">タブ3</label></li>
<li><label for="tab-4">タブ4</label></li>
<li><label for="tab-5">タブ5</label></li>
</ul>
<div class="tabContents">
<section>タブコンテンツ1</section>
<section>タブコンテンツ2</section>
<section>タブコンテンツ3</section>
<section>タブコンテンツ4</section>
<section>タブコンテンツ5</section>
</div>
タブボタンに<label>
を使うのがポイント:)。
次に、コンテンツを切り替えるスイッチの役割となる<input type="radio">
(ラジオボタン)を5つ、上記ソースコードの手前に設置します。
<input type="radio" name="switch" id="tab-1" checked>
<input type="radio" name="switch" id="tab-2">
<input type="radio" name="switch" id="tab-3">
<input type="radio" name="switch" id="tab-4">
<input type="radio" name="switch" id="tab-5">
name属性の値を統一して、ラジオボタンをひとつのグループに(ここではswitch
に)。それから<input>
のid属性の値を、<label>
のfor属性の値と同じにして、タブボタンとラジオボタンを関連付けます。
一番めの<input>
にはchecked
を付けて、初期状態では「タブコンテンツ1」が開いているようにしておきます。
以上で下ごしらえ完了!
CSS
そして、以降の指定が、コンテンツの表示/非表示を切り替えるための仕組みの部分になります。
まずは、タブボタンを切り替えた時の、ボタンのスタイルを指定します。
#tab-1:checked ~ .tabBtn li [for="tab-1"],
#tab-2:checked ~ .tabBtn li [for="tab-2"],
#tab-3:checked ~ .tabBtn li [for="tab-3"],
#tab-4:checked ~ .tabBtn li [for="tab-4"],
#tab-5:checked ~ .tabBtn li [for="tab-5"] {
background-color: #cd5c5c;
}
一番上の行を分解して見ると。
#tab-1:checked
- チェックされている「id属性が
tab-1
の要素」 ~
(チルダ)- それ以降にある同じ階層の要素(兄弟要素)
.tabBtn li [for="tab-1"]
class="tabBtn"
の要素の中の「for属性がtab-1
の要素」
つまり、チェックされている「id属性がtab-1
の要素」と同じ階層にあるclass="tabBtn"
の要素の中の「for属性がtab-1
の要素」にbackground-color: #cd5c5c
を指定する(背景色を赤くする)って事になります。
要するに「1つめのラジオボタンがチェックされてる時は、1つめのタブボタンを赤くする」ということ。
タブボタンを切り替えた時のコンテンツのスタイルもタブボタンと同じ要領で、チェックされている「id属性がtab-1
の要素」と同じ階層にあるclass="tabContents"
の要素の中の「ひとつめのsection要素」というように、タブコンテンツを特定します。
.tabContents section {
opacity: 0.1;
text-align: center;
}
#tab-1:checked ~ .tabContents section:nth-child(1),
#tab-2:checked ~ .tabContents section:nth-child(2),
#tab-3:checked ~ .tabContents section:nth-child(3),
#tab-4:checked ~ .tabContents section:nth-child(4),
#tab-5:checked ~ .tabContents section:nth-child(5) {
opacity: 1;
background-color: #fff;
}
チェックされていない時は透明(ここでは仕組みが見えるように半透明)にしておき、チェックされたボタンを不透明にすることで、表示/非表示が切り替わるというわけです。
アニメーションして切り替わる
タブコンテンツにコンテンツを入れてみました;)。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - タブコンテンツにコンテンツを入れてみました</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" name="switch" id="tab-1" checked> <input type="radio" name="switch" id="tab-2"> <input type="radio" name="switch" id="tab-3"> <input type="radio" name="switch" id="tab-4"> <input type="radio" name="switch" id="tab-5"> <ul class="tabBtn"> <li><label for="tab-1">タブ1</label></li> <li><label for="tab-2">タブ2</label></li> <li><label for="tab-3">タブ3</label></li> <li><label for="tab-4">タブ4</label></li> <li><label for="tab-5">タブ5</label></li> </ul> <div class="tabContents"> <section> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2014/01/title.png"> <figcaption>フォント好きな人がフォントについて熱く語る「LOVEFONT」という企画にあと乗りで、僕の好きなフォント「きりぎりす」について、語るってほどは語れませんが、記事にさせていただきます。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2013/09/title.jpg"> <figcaption>ちょっとざらざらした質感とか、手触りを感じるテクスチャって、背景にさりげなく敷くだけで、ほんのり暖かみが出ていいですよね。そんなざらざらノイズ画像を半透明にした「透明ノイズ」のつくり方についてまとめてみました。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2013/06/title.jpg"> <figcaption>トップページのコーディングがひと通り完了したので、下層ページのコーディングに移る前に、一旦ブラウザチェックしてみようと思います:)。ブラウザチェックからIEでの表示崩れを整えるまでのまとめです。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2013/03/title.jpg"> <figcaption>拡大しても劣化しないし、ダブルクリックでカンタンに色を変えられるし、もちろんIllustratorでも使い回せる、そんなPhotoshopの万能シェイプの機能や特長について、個人的なまとめです。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2012/12/title.jpg"> <figcaption>CSS Programming Advent Calendar 2012、22日目のための記事です。前回の記事で作った、グローバルナビの下の大きめの画像のところを、CSSだけで実装してみました。<a href="#">この記事を読む</a></figcaption> </figure> </section> </div> </div> </body> </html>
#wrapper { box-sizing: border-box; -moz-box-sizing: border-box; } [name="switch"] { display: none; } /* :::::: button :::::: */ /* 略 */ /* :::::: contents :::::: */ .tabContents { position: relative; } .tabContents section { box-sizing: border-box; -moz-box-sizing: border-box; width: 100%; padding: 20px; background-color: #fff; } .tabContents figure { overflow: hidden; } .tabContents figure img { float: left; max-width: 50%; margin-right: 20px; } .tabContents figcaption { font-size: 12px; line-height: 1.8; } /* :::::: mechanism :::::: */ .tabContents section { opacity: 0.1; transition: opacity 0.3s; } #tab-1:checked ~ .tabBtn li [for="tab-1"], #tab-2:checked ~ .tabBtn li [for="tab-2"], #tab-3:checked ~ .tabBtn li [for="tab-3"], #tab-4:checked ~ .tabBtn li [for="tab-4"], #tab-5:checked ~ .tabBtn li [for="tab-5"] { background-color: #cd5c5c; } #tab-1:checked ~ .tabContents section:nth-child(1), #tab-2:checked ~ .tabContents section:nth-child(2), #tab-3:checked ~ .tabContents section:nth-child(3), #tab-4:checked ~ .tabContents section:nth-child(4), #tab-5:checked ~ .tabContents section:nth-child(5) { opacity: 1; background-color: #fff; }
タブコンテンツも、前述のボタンの時みたく、「transition
」を使って切り替わり方をアレンジすれば、印象的な表現ができちゃいますよ。
スライドして切り替わる
タブボタンの切り替えに合わせて、<div class="tabContents">
の位置を上下にズラせば、スクロールコンテンツみたいなものもお手のもの。
上図のように、あらかじめtransform: translateY()
で、タブボタンに対応するコンテンツの位置を指定しておきます。例えば下記なら、「タブ2」がチェックされてる時には、.tabContents
を上へ20%※ズラす、ということ。※.tabContents
全体の高さを100%とした20%分。
.tabs #tab-2:checked ~ .tabContents {
transform: translateY(-20%);
-webkit-transform: translateY(-20%);
}
これをタブコンテンツ分(このサンプルでは5つ)用意し、transition
を適用すれば、上下にスライドしながらコンテンツが切り替わるようになります。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 縦にスライドして切り替わるタブコンテンツ</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述のと同じ --> </body> </html>
/* 略 */ /* :::::: slide :::::: */ .tabContents { -webkit-transition: -webkit-transform 0.6s; transition: transform 0.6s; } .tabContents section { opacity: 0.1; transition: opacity 0.3s; } /* :::::: mechanism :::::: */ #tab-1:checked ~ .tabBtn li [for="tab-1"], #tab-2:checked ~ .tabBtn li [for="tab-2"], #tab-3:checked ~ .tabBtn li [for="tab-3"], #tab-4:checked ~ .tabBtn li [for="tab-4"], #tab-5:checked ~ .tabBtn li [for="tab-5"] { background-color: #cd5c5c; } #tab-1:checked ~ .tabContents section:nth-child(1), #tab-2:checked ~ .tabContents section:nth-child(2), #tab-3:checked ~ .tabContents section:nth-child(3), #tab-4:checked ~ .tabContents section:nth-child(4), #tab-5:checked ~ .tabContents section:nth-child(5) { opacity: 1; background-color: #fff; } #tab-1:checked ~ .tabContents { -webkit-transform: translateY(0); transform: translateY(0); } #tab-2:checked ~ .tabContents { -webkit-transform: translateY(-20%); transform: translateY(-20%); } #tab-3:checked ~ .tabContents { -webkit-transform: translateY(-40%); transform: translateY(-40%); } #tab-4:checked ~ .tabContents { -webkit-transform: translateY(-60%); transform: translateY(-60%); } #tab-5:checked ~ .tabContents { -webkit-transform: translateY(-80%); transform: translateY(-80%); }
あれれ…、タブコンテンツがタブボタンの上に被さってタブボタンが押せなくなっちゃう…X(。。
こんな時は.tabBtn
にz-index
を指定して、手前に配置すれば安心。
※z-index
はpositionプロパティにstatic
以外の値が指定してある要素でないと効果がないので、position: relative
も一緒に指定。
.tabs .tabBtn {
position: relative;
z-index: 1;
}
無事タブボタンが押せるようになりました:D!
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 縦にスライドして切り替わるタブコンテンツ</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述のと同じ --> </body> </html>
/* 略 */ /* :::::: slide :::::: */ .tabBtn { position: relative; z-index: 1; } .tabContents { -webkit-transition: -webkit-transform 0.6s; transition: transform 0.6s; } .tabContents section { opacity: 0.1; transition: opacity 0.3s; } /* :::::: mechanism :::::: */ #tab-1:checked ~ .tabBtn li [for="tab-1"], #tab-2:checked ~ .tabBtn li [for="tab-2"], #tab-3:checked ~ .tabBtn li [for="tab-3"], #tab-4:checked ~ .tabBtn li [for="tab-4"], #tab-5:checked ~ .tabBtn li [for="tab-5"] { background-color: #cd5c5c; } #tab-1:checked ~ .tabContents section:nth-child(1), #tab-2:checked ~ .tabContents section:nth-child(2), #tab-3:checked ~ .tabContents section:nth-child(3), #tab-4:checked ~ .tabContents section:nth-child(4), #tab-5:checked ~ .tabContents section:nth-child(5) { opacity: 1; background-color: #fff; } #tab-1:checked ~ .tabContents { -webkit-transform: translateY(0); transform: translateY(0); } #tab-2:checked ~ .tabContents { -webkit-transform: translateY(-20%); transform: translateY(-20%); } #tab-3:checked ~ .tabContents { -webkit-transform: translateY(-40%); transform: translateY(-40%); } #tab-4:checked ~ .tabContents { -webkit-transform: translateY(-60%); transform: translateY(-60%); } #tab-5:checked ~ .tabContents { -webkit-transform: translateY(-80%); transform: translateY(-80%); }
横にスライドして切り替わる
タブコンテンツを横並びにして、transform: translateX()
で横へズラせば、横スライドもお手のもの。
.tabContents
の横幅をウィンドウ幅5つ分(500%)にして、その中にタブコンテンツを横並びにします。そのままだとスクロールバーが出てしまうので、全体を包む<div id="wrapper">
にoverflow: hidden
を指定して、スクロールバーを出さないようにすればできあがり。
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 横にスライドして切り替わるタブコンテンツ</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述のと同じ --> </body> </html>
/* 略 */ /* :::::: slide :::::: */ #wrapper { overflow: hidden; } .tabContents { width: 500%; -webkit-transition: -webkit-transform 0.6s; transition: transform 0.6s; } .tabContents section { float: left; width: 20%; opacity: 0.1; transition: opacity 0.3s; } /* :::::: mechanism :::::: */ #tab-1:checked ~ .tabBtn li [for="tab-1"], #tab-2:checked ~ .tabBtn li [for="tab-2"], #tab-3:checked ~ .tabBtn li [for="tab-3"], #tab-4:checked ~ .tabBtn li [for="tab-4"], #tab-5:checked ~ .tabBtn li [for="tab-5"] { background-color: #cd5c5c; } #tab-1:checked ~ .tabContents section:nth-child(1), #tab-2:checked ~ .tabContents section:nth-child(2), #tab-3:checked ~ .tabContents section:nth-child(3), #tab-4:checked ~ .tabContents section:nth-child(4), #tab-5:checked ~ .tabContents section:nth-child(5) { opacity: 1; background-color: #fff; } #tab-1:checked ~ .tabContents { -webkit-transform: translateX(0); transform: translateX(0); } #tab-2:checked ~ .tabContents { -webkit-transform: translateX(-20%); transform: translateX(-20%); } #tab-3:checked ~ .tabContents { -webkit-transform: translateX(-40%); transform: translateX(-40%); } #tab-4:checked ~ .tabContents { -webkit-transform: translateX(-60%); transform: translateX(-60%); } #tab-5:checked ~ .tabContents { -webkit-transform: translateX(-80%); transform: translateX(-80%); }
表示モード切り替え
ここまではいくつかのコンテンツをタブボタンで切り替えてましたが、タブボタンのON/OFFで、同一コンテンツのスタイルを変えるようにすれば、表示モード切り替えみたいな事もできます。
ここでは、「画像とテキスト全部入りのレイアウト」、「画像が主役のレイアウト」、「テキストのみのレイアウト」の3タイプの表示モードを、タブボタンで切り替えてます。
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 表示モード切り替え</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" name="switch" id="normalList" checked> <input type="radio" name="switch" id="imageList"> <input type="radio" name="switch" id="textList"> <ul class="tabBtn"> <li><label for="normalList"></label></li> <li><label for="imageList"></label></li> <li><label for="textList"></label></li> </ul> <ul class="menu"> <li><a href="#"><dl> <dt class="date"><span class="year">2014</span><span class="day">1.30</span><span class="week">Thu</span></dt> <dd class="img"><img src="http://lopan.jp/wp/wp-content/uploads/2014/01/icon_lovefont-300x300.png"></dd> <dd class="ttl">なつかしくってあったかい、きりぎりす。 #LOVEFONT</dd> <dd class="excerpt">フォント好きな人がフォントについて熱く語る「LOVEFONT」という企画にあと乗りで、僕の好きなフォント「きりぎりす」について、語るってほどは語れませんが、記事にさせていただきます。</dd> </dl></a></li> <li><a href="#"><dl> <dt class="date"><span class="year">2013</span><span class="day">9.15</span><span class="week">Sun</span></dt> <dd class="img"><span><img src="http://lopan.jp/wp/wp-content/uploads/2013/09/icon_texture.jpg"></span></dd> <dd class="ttl">透明ノイズと紙テクスチャ。</dd> <dd class="excerpt">ちょっとざらざらした質感とか、手触りを感じるテクスチャって、背景にさりげなく敷くだけで、ほんのり暖かみが出ていいですよね。そんなざらざらノイズ画像を半透明にした「透明ノイズ」のつくり方についてまとめてみました。</dd> </dl></a></li> <li><a href="#"><dl> <dt class="date"><span class="year">2013</span><span class="day">6.17</span><span class="week">Mon</span></dt> <dd class="img"><span><img src="http://lopan.jp/wp/wp-content/uploads/2013/09/icon_webdesign4.jpg"></span></dd> <dd class="ttl">Webサイトの作り方のまとめ!ブラウザチェック。</dd> <dd class="excerpt">トップページのコーディングがひと通り完了したので、下層ページのコーディングに移る前に、一旦ブラウザチェックしてみようと思います:)。ブラウザチェックからIEでの表示崩れを整えるまでのまとめです。</dd> </dl></a></li> <li><a href="#"><dl> <dt class="date"><span class="year">2013</span><span class="day">3.19</span><span class="week">Tue</span></dt> <dd class="img"><span><img src="http://lopan.jp/wp/wp-content/uploads/2013/03/icon_photoshop_shape.jpg"></span></dd> <dd class="ttl">Photoshopのシェイプでできること。</dd> <dd class="excerpt">拡大しても劣化しないし、ダブルクリックでカンタンに色を変えられるし、もちろんIllustratorでも使い回せる、そんなPhotoshopの万能シェイプの機能や特長について、個人的なまとめです。</dd> </dl></a></li> </ul> </div> </body> </html>
/* 略 */ ul, dl, dd { margin: 0; padding: 0; } ul { list-style: none; } /* :::::: button :::::: */ .tabBtn { display: table; width: 100%; margin: 0 0 5px; padding: 0; background-color: #20b2aa; text-align: right; } .tabBtn li { display: inline-block; width: 50px; border-left: 1px solid #fff; background-color: #20b2aa; text-align: center; vertical-align: middle; } .tabBtn li label { display: block; cursor: pointer; height: 18px; padding: 9px 0; color: #fff; transition: background-color .3s; } .tabBtn li label::before { content: ""; display: inline-block; overflow: hidden; width: 18px; height: 18px; background: url(../img/ico_tabs.svg) no-repeat; } .tabBtn li label[for="normalList"]::before { background-position: 0 0; } .tabBtn li label[for="imageList"]::before { background-position: -30px 0; } .tabBtn li label[for="textList"]::before { background-position: -60px 0; } .tabBtn li label:hover { background-color: rgba(205,92,92,.5); } /* :::::: contents :::::: */ .menu li, .menu dl, .menu dt, .menu dd { box-sizing: border-box; -moz-box-sizing: border-box; } .menu::after { content: ""; display: block; clear: both; } .menu li { float: left; width: 25%; padding: 2px; } .menu li a { display: block; text-decoration: none; background-color: #fff; transition: color 0.6s, background-color 0.6s, opacity 0.6s; } .menu dl { position: relative; overflow: hidden; padding: 10px; } .menu dt, .menu dd { font-size: 0.8em; line-height: 1.6; } .menu img { width: 100%; vertical-align: middle; } .menu .date, .menu .excerpt { color: #373039; } .menu .ttl { margin-bottom: 0.3em; font-size: 1em; line-height: 1.4; } .menu .excerpt { font-size: 0.7em; } /* :::::: normal :::::: */ #normalList:checked ~ .menu li { width: 50%; } #normalList:checked ~ .menu dl { height: 140px; } #normalList:checked ~ .menu a:hover { opacity: 0.6; } #normalList:checked ~ .menu .date { height: 20px; } #normalList:checked ~ .menu .img { position: relative; float: left; overflow: hidden; width: 40%; height: 100px; margin-right: 20px; margin-bottom: 0.6em; } #normalList:checked ~ .menu .img img { position: absolute; top: 50%; -webkit-transform: translateY(-50%); transform: translateY(-50%); } #normalList:checked ~ .menu .img { z-index: 1; } #normalList:checked ~ .menu dl::after { content: ""; display: block; position: absolute; bottom: 0; left: 0; width: 100%; height: 3em; background-image: -webkit-linear-gradient(bottom, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); background-image: linear-gradient(bottom, rgba(255,255,255,1) 0%, rgba(255,255,255,0) 100%); } /* :::::: image :::::: */ #imageList:checked ~ .menu .date, #imageList:checked ~ .menu .ttl { z-index: 1; position: absolute; left: 0; line-height: 1; background-color: rgba(255,255,255,0.9); } #imageList:checked ~ .menu .date { top: 15px; padding: 0.3em 5px 0.15em 15px; } #imageList:checked ~ .menu .ttl { bottom: 0; width: 100%; margin: 0; padding: 0.5em 15px 15px; font-size: 0.8em; } #imageList:checked ~ .menu .excerpt { display: none; } #imageList:checked ~ .menu .date, #imageList:checked ~ .menu .ttl { opacity: 0; -webkit-transition: opacity 0.3s, -webkit-transform 0.6s; transition: opacity 0.3s, transform 0.6s; } #imageList:checked ~ .menu .date { -webkit-transform: translateY(-100%); transform: translateY(-100%); } #imageList:checked ~ .menu .ttl { -webkit-transform: translateY(100%); transform: translateY(100%); } #imageList:checked ~ .menu a:hover { background-color: rgba(255,255,255,0.3); } #imageList:checked ~ .menu a:hover .date, #imageList:checked ~ .menu a:hover .ttl { opacity: 1; -webkit-transform: translateY(0); transform: translateY(0); transition-duration: 1s, 0.6s; } #imageList:checked ~ .menu .img { overflow: hidden; background-color: #593869; transition: background-color 0.6s 1s; } #imageList:checked ~ .menu dl .img img { -webkit-transition: opacity 1s, -webkit-transform 0.3s; transition: opacity 1s, transform 0.3s; } #imageList:checked ~ .menu:hover dl .img img { transition-duration: 1s; } #imageList:checked ~ .menu a:hover .img img { opacity: .6; -webkit-transform: scale(1.2); transform: scale(1.2); } /* :::::: text :::::: */ #textList:checked ~ .menu li { float: none; width: 100%; } #textList:checked ~ .menu li a { background-color: rgba(255,255,255,0.3); } #textList:checked ~ .menu li a:hover { background-color: #fff; } #textList:checked ~ .menu dl { padding: 0; } #textList:checked ~ .menu dl::after { content: ""; display: block; clear: both; } #textList:checked ~ .menu dt, #textList:checked ~ .menu dd { -moz-box-sizing: border-box; box-sizing: border-box; margin: 0; padding: 10px; } #textList:checked ~ .menu .date { float: left; width: 12%; margin-right: 2px; background-color: #fff; } #textList:checked ~ .menu .date span { display: block; font-size: 0.8em; line-height: 1.2; text-align: center; } #textList:checked ~ .menu .date .day { font-size: 1.2em; } #textList:checked ~ .menu .date .week { background-color: #f4f4f4; } #textList:checked ~ .menu .img { display: none; } #textList:checked ~ .menu .ttl, #textList:checked ~ .menu .excerpt { float: right; width: calc(88% - 2px); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } #textList:checked ~ .menu .ttl { padding-bottom: 0.3em; } #textList:checked ~ .menu .excerpt { padding: 0 10px; } /* :::::: media queries :::::: */ @media screen and (max-width: 480px) { .menu li { width: 50%; } #normalList:checked ~ .menu li { float: none; width: 100%; } #textList:checked ~ .menu .date { width: 20%; } #textList:checked ~ .menu .ttl, #textList:checked ~ .menu .excerpt { width: calc(80% - 2px); } } /* :::::: mechanism :::::: */ #normalList:checked ~ .tabBtn li [for="normalList"], #imageList:checked ~ .tabBtn li [for="imageList"], #textList:checked ~ .tabBtn li [for="textList"] { background-color: #cd5c5c; } #normalList:checked ~ .menu .date .year::after, #imageList:checked ~ .menu .date .year::after, #normalList:checked ~ .menu .date .day::after, #imageList:checked ~ .menu .date .day::after { content: "."; } #normalList:checked ~ .menu .date .day::after, #imageList:checked ~ .menu .date .day::after { margin-right: 0.5em; }
下記のような記述で、各モード専用のスタイルを用意しておけば、チェックされているタブボタンに合わせて、指定したスタイルが適用される仕組みです。※該当CSSは127行め〜
#normalList:checked ~ .menu elements {
/* 全部入り用のスタイル */
}
#imageList:checked ~ .menu elements {
/* 画像が主役用のスタイル */
}
#textList:checked ~ .menu elements {
/* テキストのみ用のスタイル */
}
アニメーションを加える
上のサンプルだと、transition
を指定してる所だと、前のモードのスタイルがちょっと見えちゃったり、モードの切り替わり方がちょっとかっこわるいですよね…。
下記のようにアニメーションを定義して、タブボタンが:checked
になった時に一度だけ再生するようにしてみます。モードが切り替わったときに、ちょっと間を置いてからフェードインする感じです。
@keyframes fadeIn {
0% { opacity: 0; }
30% { opacity: 0; }
100% { opacity: 1; }
}
このアニメーションをコンテンツに適用します。※該当CSSは6〜7行め
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 表示モード切り替えフェード</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述の参照 --> </body> </html>
/* 略 */ /* :::::: fade change :::::: */ input:checked ~ .menu { -webkit-animation: fadeIn 1s 0s 1; animation: fadeIn 1s 0s 1; } @-webkit-keyframes fadeIn { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } @keyframes fadeIn { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } /* :::::: mechanism :::::: */ #normalList:checked ~ .tabBtn li [for="normalList"], #imageList:checked ~ .tabBtn li [for="imageList"], #textList:checked ~ .tabBtn li [for="textList"] { background-color: #cd5c5c; } #normalList:checked ~ .menu .date .year::after, #imageList:checked ~ .menu .date .year::after, #normalList:checked ~ .menu .date .day::after, #imageList:checked ~ .menu .date .day::after { content: "."; } #normalList:checked ~ .menu .date .day::after, #imageList:checked ~ .menu .date .day::after { margin-right: 0.5em; }
ページが開いた時に一度だけフェードインしますが、タブボタンで切り替える時には、アニメーションが再生されません…X(。。
:checked
されるタブが切り替わっても「fadeIn」というアニメーションはすでに再生された後なので、それ以上は再生されないみたいです…。
そこで、下のサンプルでは、同じアニメーションを各タブ用に3つ用意して、各タブごとに違うアニメーションを指定してみます。※該当CSSは5〜18行め
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 表示モード切り替えフェード</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述の参照 --> </body> </html>
/* 略 */ /* :::::: fade change :::::: */ #normalList:checked ~ .menu { -webkit-animation: fadeIn1 1s 0s 1; animation: fadeIn1 1s 0s 1; } #imageList:checked ~ .menu { -webkit-animation: fadeIn2 1s 0s 1; animation: fadeIn2 1s 0s 1; } #textList:checked ~ .menu { -webkit-animation: fadeIn3 1s 0s 1; animation: fadeIn3 1s 0s 1; } @-webkit-keyframes fadeIn1 { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } @keyframes fadeIn1 { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } @-webkit-keyframes fadeIn2 { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } @keyframes fadeIn2 { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } @-webkit-keyframes fadeIn3 { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } @keyframes fadeIn3 { 0% { opacity: 0; } 30% { opacity: 0; } 100% { opacity: 1; } } /* :::::: mechanism :::::: */ #normalList:checked ~ .tabBtn li [for="normalList"], #imageList:checked ~ .tabBtn li [for="imageList"], #textList:checked ~ .tabBtn li [for="textList"] { background-color: #cd5c5c; } #normalList:checked ~ .menu .date .year::after, #imageList:checked ~ .menu .date .year::after, #normalList:checked ~ .menu .date .day::after, #imageList:checked ~ .menu .date .day::after { content: "."; } #normalList:checked ~ .menu .date .day::after, #imageList:checked ~ .menu .date .day::after { margin-right: 0.5em; }
:checked
されるタブが変わる度に再生するアニメーションも切り替えることで、タブを切り替える度にアニメーションが再生されるようになりましたね:D!
スライドショー
表示を切り替える仕組みは前述のタブコンテンツと全く同じ。
だけど、タブボタンの代わりに、左右の矢印ボタンでコンテンツを切り替えるようにしてます。
まずは、矢印ボタンとして機能させるための仕掛けについてまとめます。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - スライドショー</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" name="slideshow" id="switch1" checked> <input type="radio" name="slideshow" id="switch2"> <input type="radio" name="slideshow" id="switch3"> <input type="radio" name="slideshow" id="switch4"> <input type="radio" name="slideshow" id="switch5"> <div id="slideshow"> <div class="slideContents"> <section id="slide1"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide2"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide3"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> <section id="slide4"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_4"> </section> <section id="slide5"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_5"> </section> </div> <p class="arrow prev"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> <label for="switch4"></label> <label for="switch5"></label> </p> <p class="arrow next"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> <label for="switch4"></label> <label for="switch5"></label> </p> </div> </div> </body> </html>
/* :::::: slideshow :::::: */ #wrapper { overflow: hidden; width: 100%; padding: 0; } input[type="radio"] { display: none; } #slideshow { position: relative; width: 100%; } .slideContents { position: relative; background: lightSeaGreen; text-align: center; -webkit-user-select: none; user-select: none; } .slideContents { width: 500%; -webkit-transition: -webkit-transform .6s; transition: transform .6s; } .slideContents::after { content: ""; display: block; clear: both; } .slideContents section { float: left; width: 20%; -webkit-transition: opacity .6s; transition: opacity .6s; } .slideContents section img { box-sizing: border-box; -moz-box-sizing: border-box; max-width: 100%; height: auto; padding: 0 50px; vertical-align: middle; } /* :::::: slideshow mechanism :::::: */ #switch1:checked ~ #slideshow .slideContents { -webkit-transform: translateX(0); transform: translateX(0); } #switch2:checked ~ #slideshow .slideContents { -webkit-transform: translateX(-20%); transform: translateX(-20%); } #switch3:checked ~ #slideshow .slideContents { -webkit-transform: translateX(-40%); transform: translateX(-40%); } #switch4:checked ~ #slideshow .slideContents { -webkit-transform: translateX(-60%); transform: translateX(-60%); } #switch5:checked ~ #slideshow .slideContents { -webkit-transform: translateX(-80%); transform: translateX(-80%); } /* :::::: arrows :::::: */ .arrow, .arrow label, .arrow .ico { position: absolute; } .arrow { top: 0; margin: 0; transition: background .3s; } .prev { left: 0; } .next { right: 0; } .arrow:hover { background: rgba(255,255,255,.2); } .arrow, .arrow label { cursor: pointer; width: 50px; height: 100%; } .arrow label { top: 0; left: 0; z-index: 1; } .arrow .ico { top: 50%; width: 12px; height: 12px; margin-top: -6px; border-top: 3px solid #fff; border-right: 3px solid #fff; opacity: 0; transition: right .6s, left .6s, opacity .6s; } .arrow:hover .ico { opacity: .6; transition-duration: .3s; } .prev .ico { left: 60%; -webkit-transform: rotate(-135deg); transform: rotate(-135deg); } .next .ico { right: 60%; -webkit-transform: rotate(45deg); transform: rotate(45deg); } .prev:hover .ico { left: 30%; } .next:hover .ico { right: 30%; } /* :::::: arrows mechanism :::::: */ .arrow label { pointer-events: none; } #switch1:checked ~ #slideshow .prev label[for="switch5"], #switch2:checked ~ #slideshow .prev label[for="switch1"], #switch3:checked ~ #slideshow .prev label[for="switch2"], #switch4:checked ~ #slideshow .prev label[for="switch3"], #switch5:checked ~ #slideshow .prev label[for="switch4"], #switch1:checked ~ #slideshow .next label[for="switch2"], #switch2:checked ~ #slideshow .next label[for="switch3"], #switch3:checked ~ #slideshow .next label[for="switch4"], #switch4:checked ~ #slideshow .next label[for="switch5"], #switch5:checked ~ #slideshow .next label[for="switch1"] { pointer-events: auto; }
同じ方向にスライド
コンテンツ1からコンテンツ5に切り替わる時と、コンテンツ5からコンテンツ1に切り替わる時、逆方向にスライドして戻るんじゃなくて、常に同じ方向にスライドした方がスマートですよね:)。
上図みたく、スライドさせる要素を、.slideContents
じゃなく、その中のコンテンツに変えればできそうな気がします。
まずはコンテンツをposition: absolute
で、すべて同じ位置に絶対配置してから、transform: translateX(100%)
でスライドショーの横幅分右側にズラして、隠しておきます。
#slideshow .slideContents section {
position: absolute;
top: 0;
left: 0;
transform: translateX(100%);
-webkit-transform: translateX(100%);
transition: transform .6s;
-webkit-transition: -webkit-transform .6s;
}
タブボタンと同じように、#switch1:checked
の時はひとつめの<section>
を真ん中に、#switch2:checked
の時はふたつめの<section>
を真ん中に…という風に指定します。
#switch1:checked ~ #slideshow .slideContents #slide1,
#switch2:checked ~ #slideshow .slideContents #slide2,
#switch3:checked ~ #slideshow .slideContents #slide3,
#switch4:checked ~ #slideshow .slideContents #slide4,
#switch5:checked ~ #slideshow .slideContents #slide5 {
z-index: 1;
position: relative;
transform: translateX(0);
-webkit-transform: translateX(0);
}
この時にposition: relative
も一緒に指定するのがポイント。ぜんぶ絶対配置にすると.slideContents
の高さがなくなってしまうので、表示中のコンテンツだけは絶対配置じゃなくして、高さを保持します。真ん中のコンテンツも絶対配置だとこんななる。
これで、矢印ボタンをクリックして:checked
が切り替わると、それに合わせてコンテンツがスライドするようになりました!けどこれだけだと下図みたいな感じ。右側から出たり入ったりするだけになっちゃってます…。
右矢印ボタンをクリックした時には、表示中のコンテンツは左側にスライドしないといけないですよね。
つまり下図みたく、コンテンツが順繰りローテーションするような構造になります。
「コンテンツ2」表示中はコンテンツ5とコンテンツ1、「コンテンツ3」表示中はコンテンツ2とコンテンツ1という具合に、表示中のコンテンツの手前ふたつのコンテンツは左側に来るように指定すればいいっぽいです!
#switch1:checked ~ #slideshow .slideContents #slide5,
#switch1:checked ~ #slideshow .slideContents #slide4,
#switch2:checked ~ #slideshow .slideContents #slide1,
#switch2:checked ~ #slideshow .slideContents #slide5,
#switch3:checked ~ #slideshow .slideContents #slide2,
#switch3:checked ~ #slideshow .slideContents #slide1,
#switch4:checked ~ #slideshow .slideContents #slide3,
#switch4:checked ~ #slideshow .slideContents #slide2,
#switch5:checked ~ #slideshow .slideContents #slide4,
#switch5:checked ~ #slideshow .slideContents #slide3 {
transform: translateX(-100%);
-webkit-transform: translateX(-100%);
}
そしてできたのがこちら。むむ!何やらめまぐるしい…。
translateX(-100%)
からtranslateX(100%)
へ移動してくのが見えちゃってるんですね…。
端から端へ移動する時だけは、スライドじゃなくて、瞬間移動するようにしないといけません。つまりtransition-duration
(変化にかかる時間)を0秒にすればいいって事ですね!
#switch1:checked ~ #slideshow .slideContents #slide3,
#switch1:checked ~ #slideshow .slideContents #slide4,
#switch2:checked ~ #slideshow .slideContents #slide4,
#switch2:checked ~ #slideshow .slideContents #slide5,
#switch3:checked ~ #slideshow .slideContents #slide5,
#switch3:checked ~ #slideshow .slideContents #slide1,
#switch4:checked ~ #slideshow .slideContents #slide1,
#switch4:checked ~ #slideshow .slideContents #slide2,
#switch5:checked ~ #slideshow .slideContents #slide2,
#switch5:checked ~ #slideshow .slideContents #slide3 {
transition-duration: 0s;
}
そんなこんなで、できあがり!
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 同じ方向にスライドするスライドショー</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述の参照 --> </body> </html>
/* :::::: slideshow :::::: */ #wrapper { overflow: hidden; width: 100%; padding: 0; } input[type="radio"] { display: none; } #slideshow { position: relative; width: 100%; } .slideContents { position: relative; background: lightSeaGreen; text-align: center; -webkit-user-select: none; user-select: none; } .slideContents, .slideContents section { width: 100%; height: auto; } .slideContents section { position: absolute; top: 0; left: 0; -webkit-transform: translateX(100%); transform: translateX(100%); -webkit-transition: opacity .6s, -webkit-transform .6s; transition: opacity .6s, transform .6s; } .slideContents section img { box-sizing: border-box; -moz-box-sizing: border-box; max-width: 100%; height: auto; padding: 0 50px; vertical-align: middle; } /* :::::: slideshow mechanism :::::: */ #switch1:checked ~ #slideshow .slideContents #slide1, #switch2:checked ~ #slideshow .slideContents #slide2, #switch3:checked ~ #slideshow .slideContents #slide3, #switch4:checked ~ #slideshow .slideContents #slide4, #switch5:checked ~ #slideshow .slideContents #slide5 { z-index: 1; position: relative; -webkit-transform: translateX(0); transform: translateX(0); } #switch1:checked ~ #slideshow .slideContents #slide1, #switch2:checked ~ #slideshow .slideContents #slide2, #switch3:checked ~ #slideshow .slideContents #slide3, #switch4:checked ~ #slideshow .slideContents #slide4, #switch5:checked ~ #slideshow .slideContents #slide5 { opacity: 1; } #switch1:checked ~ #slideshow .slideContents #slide5, #switch1:checked ~ #slideshow .slideContents #slide4, #switch2:checked ~ #slideshow .slideContents #slide1, #switch2:checked ~ #slideshow .slideContents #slide5, #switch3:checked ~ #slideshow .slideContents #slide2, #switch3:checked ~ #slideshow .slideContents #slide1, #switch4:checked ~ #slideshow .slideContents #slide3, #switch4:checked ~ #slideshow .slideContents #slide2, #switch5:checked ~ #slideshow .slideContents #slide4, #switch5:checked ~ #slideshow .slideContents #slide3 { -webkit-transform: translateX(-100%); transform: translateX(-100%); } #switch1:checked ~ #slideshow .slideContents #slide3, #switch2:checked ~ #slideshow .slideContents #slide4, #switch3:checked ~ #slideshow .slideContents #slide5, #switch4:checked ~ #slideshow .slideContents #slide1, #switch5:checked ~ #slideshow .slideContents #slide2, #switch1:checked ~ #slideshow .slideContents #slide4, #switch2:checked ~ #slideshow .slideContents #slide5, #switch3:checked ~ #slideshow .slideContents #slide1, #switch4:checked ~ #slideshow .slideContents #slide2, #switch5:checked ~ #slideshow .slideContents #slide3 { transition-duration: 0s; } /* :::::: arrows :::::: */ /* 略 */
6秒おきに切り替わる
スライドショーなら、自動でスライドさせてみたいです。
animationプロパティを使って、スライドするアニメーションを、各コンテンツに個別に指定して、タイミングよく順番にスライドさせれば、できそうな気がします:D!
まずはアニメーションのキーフレームを作ります。
5つのコンテンツを順番にスライドさせるので、コンテンツひとつにつき、表示される時間は、全体の20%ずつ割り振れます。アニメーション全体の長さを100%秒とすると、各コンテンツのアニメーションの一連の流れは、下図みたいな感じになると思います。
0%秒から16%秒までは真ん中でじっとしてる。
16%秒から20%秒にかけて、真ん中から左側へスライド。
右側へ瞬間移動。
22%秒から96%秒までは右側でじっとしてる。
96%秒から100%秒にかけて、右側から真ん中へスライド。
@keyframes autoplay {
0% { transform: translateX(0); }
16% { transform: translateX(0); }
20% { transform: translateX(-100%); }
20.001% { transform: translateX(100%); }
96% { transform: translateX(100%); }
100% { transform: translateX(0); }
}
瞬間移動のところは、@keyframes
では同じパーセント値を指定すると、後に書いた指定が優先されてしまうので、パーセント値をほんのちょっとズラして、瞬間的に移動するようにしてます。
そして、上で定義したautoplay
を、スライドさせるコンテンツに指定します。
#slideshow .slideContents section {
animation: autoplay 30s infinite;
-webkit-animation: autoplay 30s infinite;
}
autoplay
というアニメーションを、30秒かけて、繰り返し再生すよう指定しました。なので20%秒がちょうど6秒になります:)。
ただし、このままだと全部のコンテンツが重なってスライドしてる状態。6秒後には全コンテンツが一緒にスライドして、何もなくなっちゃいます…X(。24秒後にまた戻ってきます。
各コンテンツのアニメーションの開始位置をちょっとずつズラせば、同じキーフレームを使って、コンテンツを順番にスライドさせることができます。
animation-delay
を使って、下記のように指定します。
#slideshow .slideContents #slide1 { animation-delay: 0; }
#slideshow .slideContents #slide2 { animation-delay: -24s; }
#slideshow .slideContents #slide3 { animation-delay: -18s; }
#slideshow .slideContents #slide4 { animation-delay: -12s; }
#slideshow .slideContents #slide5 { animation-delay: -6s; }
animation-delayプロパティにマイナスの値を指定すると、その分進んだ時点からアニメーションを開始するので、上記指定で、下図のように開始位置がズレるわけですねー。
できましたー!
けど、矢印ボタンをクリックしても何も起こりません…。
矢印ボタンではtransform: translateX()
の値を切り替えてスライドさせたんですが、アニメーション中は@keyframesルールで定義したスタイルの方が優先されるので、矢印ボタンで切り替えてもびくともしないんですね…。自動スライドと矢印ボタンの併用はできなさそう…¦(。
そんなわけで、矢印ボタンをなくして、できあがり!
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 同じ方向にスライドするスライドショー</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <div id="slideshow"> <div class="slideContents"> <section id="slide1"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide2"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide3"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> <section id="slide4"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_4"> </section> <section id="slide5"> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_5"> </section> </div> </div> </div> </body> </html>
/* 略 */ /* :::::: timer mechanism :::::: */ .slideContents section { -webkit-animation: autoplay 30s infinite; animation: autoplay 30s infinite; } .slideContents section { -webkit-transform: none; transform: none; transition: none; } .slideContents #slide1 { position: relative; -webkit-animation-delay: 0; animation-delay: 0; } .slideContents #slide2 { -webkit-animation-delay: -24s; animation-delay: -24s; } .slideContents #slide3 { -webkit-animation-delay: -18s; animation-delay: -18s; } .slideContents #slide4 { -webkit-animation-delay: -12s; animation-delay: -12s; } .slideContents #slide5 { -webkit-animation-delay: -6s; animation-delay: -6s; } @-webkit-keyframes autoplay { 0% { -webkit-transform: translateX(0); } 16% { -webkit-transform: translateX(0); } 20% { -webkit-transform: translateX(-100%); } 20.001% { -webkit-transform: translateX(100%); } 96% { -webkit-transform: translateX(100%); } 100% { -webkit-transform: translateX(0); } } @keyframes autoplay { 0% { transform: translateX(0); } 16% { transform: translateX(0); } 20% { transform: translateX(-100%); } 20.001% { transform: translateX(100%); } 96% { transform: translateX(100%); } 100% { transform: translateX(0); } }
演出を加える
スライドしてきた時にテキストだけ後から出てくるとか、イラストだけチロチロ動いてるとか、切り替わる時にほんの少しの動きを加えてみます。より印象的になること請け合いです:)。
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - スライドショーに演出を加える</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" id="switch1" name="slideshow" checked> <input type="radio" id="switch2" name="slideshow"> <input type="radio" id="switch3" name="slideshow"> <input type="radio" id="switch4" name="slideshow"> <input type="radio" id="switch5" name="slideshow"> <div id="slideshow"> <div class="slideContents"> <section id="slide1"> <div class="contents"> <h1>奥行きがある感じ</h1> <p>スライドする距離を変えれば、やんわりパララックス。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide2"> <div class="contents"> <h1>遅れて出てくる</h1> <p>スライドするタイミングをずらして、さりげなくアクセント。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide3"> <div class="contents"> <h1>要素を立体的に</h1> <p>3Dtransformを使って、さらに立体感。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> <section id="slide4"> <div class="contents"> <h1>アニメーションする</h1> <p>animationプロパティを使って、ほんのりアピール。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_4"> </section> <section id="slide5"> <div class="contents"> <h1><span>いろいろアニメーション</span></h1> <p>飛んだり跳ねたりブルブルしたりして、賑やかし。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_5"> </section> </div> <p class="arrow prev"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> <label for="switch4"></label> <label for="switch5"></label> </p> <p class="arrow next"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> <label for="switch4"></label> <label for="switch5"></label> </p> </div> </div> </body> </html>
/* 略 */ /* :::::: contents :::::: */ .slideContents section { opacity: 0; } .slideContents section .contents { box-sizing: border-box; -moz-box-sizing: border-box; position: absolute; top: 0; left: 50%; width: 600px; height: 200px; margin-left: -300px; padding: 20px; } .slideContents section h1, .slideContents section p { color: lightseagreen; opacity: 0; } .slideContents section h1 { margin: 0; font-size: 16px; } .slideContents section p { font-size: 12px; } /* :::::: slideshow mechanism :::::: */ #switch1:checked ~ #slideshow .slideContents #slide1, #switch2:checked ~ #slideshow .slideContents #slide2, #switch3:checked ~ #slideshow .slideContents #slide3, #switch4:checked ~ #slideshow .slideContents #slide4, #switch5:checked ~ #slideshow .slideContents #slide5 { z-index: 1; position: relative; -webkit-transform: translateX(0); transform: translateX(0); } #switch1:checked ~ #slideshow .slideContents #slide1, #switch2:checked ~ #slideshow .slideContents #slide2, #switch3:checked ~ #slideshow .slideContents #slide3, #switch4:checked ~ #slideshow .slideContents #slide4, #switch5:checked ~ #slideshow .slideContents #slide5 { opacity: 1; } #switch1:checked ~ #slideshow .slideContents #slide5, #switch1:checked ~ #slideshow .slideContents #slide4, #switch2:checked ~ #slideshow .slideContents #slide1, #switch2:checked ~ #slideshow .slideContents #slide5, #switch3:checked ~ #slideshow .slideContents #slide2, #switch3:checked ~ #slideshow .slideContents #slide1, #switch4:checked ~ #slideshow .slideContents #slide3, #switch4:checked ~ #slideshow .slideContents #slide2, #switch5:checked ~ #slideshow .slideContents #slide4, #switch5:checked ~ #slideshow .slideContents #slide3 { -webkit-transform: translateX(-100%); transform: translateX(-100%); } #switch1:checked ~ #slideshow .slideContents #slide3, #switch2:checked ~ #slideshow .slideContents #slide4, #switch3:checked ~ #slideshow .slideContents #slide5, #switch4:checked ~ #slideshow .slideContents #slide1, #switch5:checked ~ #slideshow .slideContents #slide2, #switch1:checked ~ #slideshow .slideContents #slide4, #switch2:checked ~ #slideshow .slideContents #slide5, #switch3:checked ~ #slideshow .slideContents #slide1, #switch4:checked ~ #slideshow .slideContents #slide2, #switch5:checked ~ #slideshow .slideContents #slide3 { transition-duration: 0s; } /* :::::: arrows :::::: */ /* 略 */ /* 奥行きがある感じ * 遅れて出てくる * 要素を立体的に * アニメーションする * いろいろアニメーション * * それぞれ、以下項のソース参照。 */
上のサンプルでは、これまでのスライドショーに、h1要素とp要素を追加してみました。
<img>
の上に<div class="contents">
を重ねて、その中に<h1>
と<p>
を入れてる構造になります。
コンテンツと、その中のh1要素とp要素、それぞれの動きを個別に変えることで、スライドしてくる時のコンテンツにちょっとしたアクセントを付けてます。
コンテンツ1〜3まではtransitionプロパティを使って、コンテンツ4と5はanimationプロパティを使って、動きの違いを表現しています。
それでは、順番に(おおざっぱに)解説です!
奥行きがある感じ
h1要素とp要素の初期位置(左右に隠れてる時の位置)を、コンテンツの中心よりズラして配置し、コンテンツのスライドに合わせて徐々に中央に来るようスライドしてます。
遠くからスライドしてくる要素ほど速く動くので、やんわり遠近感が感じられる表現になるってわけで、これがパララックスってやつです。
よりパララックスがじっくり感じられるように、コンテンツ自体とh1要素とp要素それぞれに、transition-timing-function
で、ゆっくり始まってゆっくり終わる「easeInOutCubic」というイージングを適用したりしてます。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 奥行きがある感じのスライドショー</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" id="switch1" name="slideshow" checked> <input type="radio" id="switch2" name="slideshow"> <input type="radio" id="switch3" name="slideshow"> <div id="slideshow"> <div class="slideContents"> <section id="slide01"> <div class="contents"> <h1>奥行きがある感じ</h1> <p>スライドする距離を変えれば、やんわりパララックス。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide02"> <div class="contents"> <h1>奥行きがある感じ</h1> <p>スライドする距離を変えれば、やんわりパララックス。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide03"> <div class="contents"> <h1>奥行きがある感じ</h1> <p>スライドする距離を変えれば、やんわりパララックス。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> </div> <p class="arrow prev"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> <p class="arrow next"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> </div> </div> </body> </html>
/* 略 */ /* :::::: action mechanism :::::: */ .slideContents section, .slideContents section h1, .slideContents section p { -webkit-transition: opacity 1s, -webkit-transform 1s; transition: opacity 1s, transform 1s; } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { opacity: 1; } /* 奥行きがある感じ */ .slideContents section, .slideContents section h1, .slideContents section p { transition-timing-function: cubic-bezier(0.645, 0.045, 0.355, 1); /* easeInOutCubic */ } #switch1:checked ~ #slideshow .slideContents #slide01, #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); /* easeOutCubic */ } .slideContents section h1 { -webkit-transform: translateX(400px); transform: translateX(400px); } .slideContents section p { -webkit-transform: translateX(200px); transform: translateX(200px); } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { -webkit-transform: translateX(0); transform: translateX(0); } #switch2:checked ~ #slideshow .slideContents #slide01 h1, #switch3:checked ~ #slideshow .slideContents #slide02 h1, #switch1:checked ~ #slideshow .slideContents #slide03 h1 { -webkit-transform: translateX(-400px); transform: translateX(-400px); } #switch2:checked ~ #slideshow .slideContents #slide01 p, #switch3:checked ~ #slideshow .slideContents #slide02 p, #switch1:checked ~ #slideshow .slideContents #slide03 p { -webkit-transform: translateX(-200px); transform: translateX(-200px); }
遅れて出てくる
コンテンツ自体の動きは変えずに、h1要素とp要素の動きをちょっと変えてるだけ。
上のサンプルと同じように、h1要素とp要素の初期位置をコンテンツの中心よりズラして配置し、transition-delay
で、0.3秒ずつ遅れて出てくるように指定したり、transition-duration
で、コンテンツよりも、変化にかかる時間を長めに指定してます。
さらに、変化の仕方をtransition-timing-function
で、ちょっと行き過ぎて戻る、既存の「easeOutBack」というイージングを、緩めにアレンジしたものを適用。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 遅れて出てくるスライドショー</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" id="switch1" name="slideshow" checked> <input type="radio" id="switch2" name="slideshow"> <input type="radio" id="switch3" name="slideshow"> <div id="slideshow"> <div class="slideContents"> <section id="slide01"> <div class="contents"> <h1>遅れて出てくる</h1> <p>スライドするタイミングをずらして、さりげなくアクセント。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide02"> <div class="contents"> <h1>遅れて出てくる</h1> <p>スライドするタイミングをずらして、さりげなくアクセント。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide03"> <div class="contents"> <h1>遅れて出てくる</h1> <p>スライドするタイミングをずらして、さりげなくアクセント。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> </div> <p class="arrow prev"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> <p class="arrow next"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> </div> </div> </body> </html>
/* 略 */ /* :::::: action mechanism :::::: */ .slideContents section, .slideContents section h1, .slideContents section p { -webkit-transition: opacity 1s, -webkit-transform 1s; transition: opacity 1s, transform 1s; } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { opacity: 1; } /* 遅れて出てくる */ .slideContents section h1, .slideContents section p { transition-duration: 1.2s; transition-timing-function: cubic-bezier(.1,1.3,.3,1); /* easeOutBackを緩めた感じ */ } .slideContents section h1 { transition-delay: .3s; } .slideContents section p { transition-delay: .6s; } .slideContents section h1, .slideContents section p { -webkit-transform: translateX(600px); transform: translateX(600px); } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { -webkit-transform: translateX(0); transform: translateX(0); } #switch3:checked ~ #slideshow .slideContents #slide02 h1, #switch3:checked ~ #slideshow .slideContents #slide02 p, #switch1:checked ~ #slideshow .slideContents #slide03 h1, #switch1:checked ~ #slideshow .slideContents #slide03 p, #switch2:checked ~ #slideshow .slideContents #slide01 h1, #switch2:checked ~ #slideshow .slideContents #slide01 p { -webkit-transform: translateX(-600px); transform: translateX(-600px); }
要素を立体的に
コンテンツの初期状態(左右に隠れてる時の状態)を、コンテンツの表面が内側を向くように、横に90°回転した状態にしてます。
その時にちゃんと立体的な表現になるように、親要素<div class="slideContents">
にperspectiveプロパティを追加。
#slideshow .slideContents {
perspective: 1000px;
-webkit-perspective: 1000px;
}
回転する様子がよく見れるように、初期位置をいつもより手前に指定したり、回転の最中に透明になるように、透明度だけtransition-duration
を短めにしたり、アニメーション具合を確認しながら、満足な動きになるまで適宜、微調整。
したりなんだりで、できあがり。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - スライドショーの要素を立体的に</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" id="switch1" name="slideshow" checked> <input type="radio" id="switch2" name="slideshow"> <input type="radio" id="switch3" name="slideshow"> <div id="slideshow"> <div class="slideContents"> <section id="slide01"> <div class="contents"> <h1>要素を立体的に</h1> <p>3Dtransformを使って、さらに立体感。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide02"> <div class="contents"> <h1>要素を立体的に</h1> <p>3Dtransformを使って、さらに立体感。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide03"> <div class="contents"> <h1>要素を立体的に</h1> <p>3Dtransformを使って、さらに立体感。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> </div> <p class="arrow prev"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> <p class="arrow next"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> </div> </div> </body> </html>
/* 略 */ /* :::::: action mechanism :::::: */ .slideContents section, .slideContents section h1, .slideContents section p { -webkit-transition: opacity 1s, -webkit-transform 1s; transition: opacity 1s, transform 1s; } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { opacity: 1; } /* 要素を立体的に */ .slideContents { -webkit-perspective: 1000px; perspective: 1000px; } .slideContents section h1 { transition-delay: .6s, 0s; } .slideContents section p { transition-delay: .4s, 0s; } .slideContents section { -webkit-transform: translateX(500px) rotateY(-90deg); transform: translateX(500px) rotateY(-90deg); transition-duration: .8s, 1.2s; } #switch1:checked ~ #slideshow .slideContents #slide01, #switch2:checked ~ #slideshow .slideContents #slide02, #switch3:checked ~ #slideshow .slideContents #slide03 { -webkit-transform: translateX(0) rotateY(0deg); transform: translateX(0) rotateY(0deg); transition-delay: .2s, 0s; } #switch2:checked ~ #slideshow .slideContents #slide01, #switch3:checked ~ #slideshow .slideContents #slide02, #switch1:checked ~ #slideshow .slideContents #slide03 { -webkit-transform: translateX(-500px) rotateY(90deg); transform: translateX(-500px) rotateY(90deg); }
アニメーションする
スライドする時の動きは変えずに、スライドした後、一度だけ、h1要素とp要素をアニメーションさせてます。
h1要素がぽよんと出てくる「h1Appear
」というアニメーションと、同じくp要素がぽよんと出てくる「pAppear
」というアニメーションを用意し、#switch4
がチェックされた時に一度だけ再生するよう、指定します。
#switch4:checked ~ #slideshow .slideContents #slide4 h1 {
-webkit-animation: h1Appear 1.5s;
}
#switch4:checked ~ #slideshow .slideContents #slide4 p {
-webkit-animation: pAppear 1.3s;
}
#switch4:checked
のh1要素とp要素だけにanimation
を指定する事で、真ん中にスライドする時だけ、アニメーションが適用されます。※キーフレームの定義は47行め〜
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - アニメーションするスライドショー</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" id="switch1" name="slideshow" checked> <input type="radio" id="switch2" name="slideshow"> <input type="radio" id="switch3" name="slideshow"> <div id="slideshow"> <div class="slideContents"> <section id="slide01"> <div class="contents"> <h1>アニメーションする</h1> <p>animationプロパティを使って、ほんのりアピール。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide02"> <div class="contents"> <h1>アニメーションする</h1> <p>animationプロパティを使って、ほんのりアピール。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide03"> <div class="contents"> <h1>アニメーションする</h1> <p>animationプロパティを使って、ほんのりアピール。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> </div> <p class="arrow prev"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> <p class="arrow next"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> </div> </div> </body> </html>
/* 略 */ /* :::::: action mechanism :::::: */ .slideContents section, .slideContents section h1, .slideContents section p { -webkit-transition: opacity 1s, -webkit-transform 1s; transition: opacity 1s, transform 1s; } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { opacity: 1; } /* アニメーションする */ .slideContents section h1, .slideContents section p { -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { transition: none; } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch3:checked ~ #slideshow .slideContents #slide03 h1 { -webkit-animation: titleAppear 1.5s; animation: titleAppear 1.5s; } #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 p { -webkit-animation: textAppear 1.3s; animation: textAppear 1.3s; } @-webkit-keyframes titleAppear { 0% { opacity: 0; } 68% { opacity: 0; -webkit-transform: translateY(6px) scaleY(1); } 75% { opacity: 1; -webkit-transform: translateY(6px) scaleY(.8); } 100% { -webkit-transform: translateY(0) scaleY(1); } } @-webkit-keyframes textAppear { 0% { opacity: 0; } 60% { opacity: 0; -webkit-transform: translateY(10px) scaleY(1); } 68% { opacity: 1; -webkit-transform: translateY(10px) scaleY(.6); } 95% { -webkit-transform: translateY(0) scaleY(1); } } @keyframes titleAppear { 0% { opacity: 0; } 68% { opacity: 0; transform: translateY(6px) scaleY(1); } 75% { opacity: 1; transform: translateY(6px) scaleY(.8); } 100% { transform: translateY(0) scaleY(1); } } @keyframes textAppear { 0% { opacity: 0; } 60% { opacity: 0; transform: translateY(10px) scaleY(1); } 68% { opacity: 1; transform: translateY(10px) scaleY(.6); } 95% { transform: translateY(0) scaleY(1); } }
いろいろアニメーション
これも、スライドする時の動きは変えず、h1要素とp要素に、個別にアニメーションを適用しています。
h1要素にはその中にspan要素を入れてて、h1
には上下に跳ねるアニメーションを指定し、span
には前後に回転するアニメーションを指定することで、宙返りするアニメーションを表現しています。
p要素は、translate()
で上下左右に移動と、rotate()
で傾きを、アニメーション具合を確認しながら、良い感じなランダムになるよう適宜、微調整。
- HTML
- CSS
- PREVIEW
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - いろいろアニメーションスライドショー</title> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <div id="wrapper"> <input type="radio" id="switch1" name="slideshow" checked> <input type="radio" id="switch2" name="slideshow"> <input type="radio" id="switch3" name="slideshow"> <div id="slideshow"> <div class="slideContents"> <section id="slide01"> <div class="contents"> <h1><span>いろいろアニメーション</span></h1> <p>飛んだり跳ねたりブルブルしたりして、賑やかし。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_1"> </section> <section id="slide02"> <div class="contents"> <h1><span>いろいろアニメーション</span></h1> <p>飛んだり跳ねたりブルブルしたりして、賑やかし。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_2"> </section> <section id="slide03"> <div class="contents"> <h1><span>いろいろアニメーション</span></h1> <p>飛んだり跳ねたりブルブルしたりして、賑やかし。</p> </div> <img src="http://placehold.it/600x200/fafafa/20b2aa/&text=slide_3"> </section> </div> <p class="arrow prev"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> <p class="arrow next"> <i class="ico"></i> <label for="switch1"></label> <label for="switch2"></label> <label for="switch3"></label> </p> </div> </div> </body> </html>
/* 略 */ /* :::::: action mechanism :::::: */ .slideContents section, .slideContents section h1, .slideContents section p { -webkit-transition: opacity 1s, -webkit-transform 1s; transition: opacity 1s, transform 1s; } #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { opacity: 1; } /* いろいろアニメーション */ #switch1:checked ~ #slideshow .slideContents #slide01 h1, #switch1:checked ~ #slideshow .slideContents #slide01 p, #switch2:checked ~ #slideshow .slideContents #slide02 h1, #switch2:checked ~ #slideshow .slideContents #slide02 p, #switch3:checked ~ #slideshow .slideContents #slide03 h1, #switch3:checked ~ #slideshow .slideContents #slide03 p { transition: none; } .slideContents section h1 { -webkit-perspective: 500px; perspective: 500px; -webkit-transform-origin: 50% 100%; transform-origin: 50% 100%; -webkit-animation: jump .5s cubic-bezier(0.215, 0.61, 0.355, 1) infinite alternate; animation: jump .5s cubic-bezier(0.215, 0.61, 0.355, 1) infinite alternate; } .slideContents section h1 span { display: block; -webkit-animation: rotate 2s infinite; animation: rotate 2s infinite; } .slideContents section p { -webkit-animation: shake .3s infinite alternate; animation: shake .3s infinite alternate; } @-webkit-keyframes shake { 0% { -webkit-transform: translate(0) rotate(0deg); } 10% { -webkit-transform: translate(-3px, -2px) rotate(-1.5deg); } 20% { -webkit-transform: translate(1px, -1px) rotate(1deg); } 30% { -webkit-transform: translate(-2px, -2px) rotate(-.6deg); } 40% { -webkit-transform: translate(3px, 3px) rotate(.5deg); } 50% { -webkit-transform: translate(0) rotate(0deg); } 60% { -webkit-transform: translate(-3px, -4px) rotate(-1deg); } 70% { -webkit-transform: translate(1px, -4px) rotate(1.5deg); } 80% { -webkit-transform: translate(-3px, -2px) rotate(-.3deg); } 90% { -webkit-transform: translate(3px, 2px) rotate(.4deg); } 100% { -webkit-transform: translate(0) rotate(0deg); } } @-webkit-keyframes jump { 0% { -webkit-transform: translateY(0); } 100% { -webkit-transform: translateY(-10px); } } @-webkit-keyframes rotate { 0% { -webkit-transform: rotateX(0deg); } 5% { -webkit-transform: rotateX(0deg); } 45% { -webkit-transform: rotateX(-180deg); } 65% { -webkit-transform: rotateX(-180deg); } 95% { -webkit-transform: rotateX(-360deg); } 100% { -webkit-transform: rotateX(-360deg); } } @keyframes shake { 0% { transform: translate(0) rotate(0deg); } 10% { transform: translate(-3px, -2px) rotate(-1.5deg); } 20% { transform: translate(1px, -1px) rotate(1deg); } 30% { transform: translate(-2px, -2px) rotate(-.6deg); } 40% { transform: translate(3px, 3px) rotate(.5deg); } 50% { transform: translate(0) rotate(0deg); } 60% { transform: translate(-3px, -4px) rotate(-1deg); } 70% { transform: translate(1px, -4px) rotate(1.5deg); } 80% { transform: translate(-3px, -2px) rotate(-.3deg); } 90% { transform: translate(3px, 2px) rotate(.4deg); } 100% { transform: translate(0) rotate(0deg); } } @keyframes jump { 0% { transform: translateY(0); } 100% { transform: translateY(-10px); } } @keyframes rotate { 0% { transform: rotateX(0deg); } 5% { transform: rotateX(0deg); } 45% { transform: rotateX(-180deg); } 65% { transform: rotateX(-180deg); } 95% { transform: rotateX(-360deg); } 100% { transform: rotateX(-360deg); } }
以上!ほとんど適宜、微調整です…。ちょっと考えて、ちょっと試して、ちょっと考えて、ちょっとずついじりながら動きを作っくのは楽しいですよー;)。
パララックス
JavaScriptでパララックスな表現をする場合には、要素ごとにスクロールスピードを変えることで、視差効果を生み出してたと思いますが、CSSではtransform
の3D表現を使って、要素を実際に画面の手前と奥に配置することで、パララックスを表現できます:)。※Internet Explorer、Firefoxでは確認できません…。
手前にパララックス
そんな訳で、要素を手前に配置して、パララックスしてみます!下図のような感じに、各要素を手前へ移動させることにしました。
手前への移動はtransformプロパティのtranslateZ()
を使います。
それから親要素には、遠近感を決めるためのperspectiveプロパティを指定します。ここでは200px
として、200px離れたところから見てる感じにします。
遠近感の基準点(消失点)は、transform-originプロパティを指定してないので、初期値の親要素の中央になります。
.parallax #wrapper {
perspective: 200px;
}
けど、下のサンプルは上手くいってませんねー…。
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 手前にパララックス</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body class="front parallax index"> <div id="wrapper"> <div class="contents"> <header> <h1 class="logo">Lopan.jp</h1> <nav> <ul> <li><a href="#article1">LOVE FONT</a></li> <li><a href="#article2">透明ノイズ</a></li> <li><a href="#article3">ブラウザチェック</a></li> <li><a href="#article4">シェイプ</a></li> <li><a href="#article5">スライドショー</a></li> </ul> </nav> </header> <article> <h1>Sample</h1> <section id="article1"> <h2>なつかしくってあったかい、きりぎりす。</h2> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2014/01/title.png"> <figcaption>フォント好きな人がフォントについて熱く語る「LOVEFONT」という企画にあと乗りで、僕の好きなフォント「きりぎりす」について、語るってほどは語れませんが、記事にさせていただきます。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section id="article2"> <h2>透明ノイズと紙テクスチャ。</h2> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2013/09/title.jpg"> <figcaption>ちょっとざらざらした質感とか、手触りを感じるテクスチャって、背景にさりげなく敷くだけで、ほんのり暖かみが出ていいですよね。そんなざらざらノイズ画像を半透明にした「透明ノイズ」のつくり方についてまとめてみました。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section id="article3"> <h2>Webサイトの作り方のまとめ!ブラウザチェック。</h2> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2013/06/title.jpg"> <figcaption>トップページのコーディングがひと通り完了したので、下層ページのコーディングに移る前に、一旦ブラウザチェックしてみようと思います:)。ブラウザチェックからIEでの表示崩れを整えるまでのまとめです。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section id="article4"> <h2>Photoshopのシェイプでできること。</h2> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2013/03/title.jpg"> <figcaption>拡大しても劣化しないし、ダブルクリックでカンタンに色を変えられるし、もちろんIllustratorでも使い回せる、そんなPhotoshopの万能シェイプの機能や特長について、個人的なまとめです。<a href="#">この記事を読む</a></figcaption> </figure> </section> <section id="article5"> <h2>CSSだけでスライドショーはつくれるよ。</h2> <figure> <img src="http://lopan.jp/wp/wp-content/uploads/2012/12/title.jpg"> <figcaption>CSS Programming Advent Calendar 2012、22日目のための記事です。前回の記事で作った、グローバルナビの下の大きめの画像のところを、CSSだけで実装してみました。<a href="#">この記事を読む</a></figcaption> </figure> </section> </article> <footer> <p class="copyright"><small>© Lopan.jp</small></p> </footer> </div> </div> </body> </html>
/* :::::: contents :::::: */ /* コンテンツ部分は「画面の端からニュッと出るメニュー」の項参照 */ /* :::::: parallax :::::: */ #wrapper { -webkit-perspective: 200px; perspective: 200px; } nav { -webkit-transform: translateZ(50px); transform: translateZ(50px); } h2 { -webkit-transform: translateZ(20px); transform: translateZ(20px); } figure img { -webkit-transform: translateZ(60px); transform: translateZ(60px); } figure figcaption a { -webkit-transform: translateZ(40px); transform: translateZ(40px); }
要素は手前に移動してるみたいですけれど、遠近感の基準点がサイト全体の中心になってるので、全体的に縦に広がっちゃってますね。しかも基準点ごとスクロールしてるので、パララックスしないわけです…X(。
サイト全体の中心じゃなくて、下図みたく、常にウィンドウの中心が基準になるようにすれば、上手くパララックスする気がします…!
なので、親要素の#wrapper
の大きさをウィンドウの大きさと同じになるよう、下記指定を加えます。
さらに#wrapper
にはoverflowプロパティを指定してスクロールバーを出して、「#wrapper
の中でコンテンツがスクロールする」ようにしてみました。
html, body, #wrapper {
height: 100%;
}
#wrapper {
overflow: auto;
}
これで、下図のような構造になりました。
#wrapper
はウィンドウの大きさに固定で、その中身だけ、#wrapper
の中でスクロールします。
ちゃんとパララックスするようになりましたー:D!
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 手前にパララックス</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述と同じ --> </body> </html>
/* :::::: contents :::::: */ /* コンテンツ部分は「画面の端からニュッと出るメニュー」の項参照 */ /* :::::: parallax :::::: */ html, body, #wrapper { height: 100%; } #wrapper { overflow: auto; -webkit-perspective: 200px; perspective: 200px; } nav { -webkit-transform: translateZ(50px); transform: translateZ(50px); } h2 { -webkit-transform: translateZ(20px); transform: translateZ(20px); } figure img { -webkit-transform: translateZ(60px); transform: translateZ(60px); } figure figcaption a { -webkit-transform: translateZ(40px); transform: translateZ(40px); }
手前のものほど大きくなっちゃってるので、できれば各要素の大きさは元通りにしたいですね。各要素にtransformプロパティにscale()
を指定して、調整してみたいと思います。
視点から要素までの距離と、大きさの関係は下図みたいになると思います。
距離が近づくほど、反比例して大きくなって見えるんですねー。
例えば、400px離れたところにある要素は、実際の大きさの半分に見えてる事になるので、元の大きさに戻すには、2倍に拡大すればよいという事になります。
100pxのところにある要素なら、2倍の大きさに見えてるので、元の大きさに戻すには、2分の1に縮小(0.5倍)すればよいという事になります。
つまり「要素までの距離 / 基準の距離 = 拡大する値」ということになりますね!
アイキャッチ画像の場合なら、60px手前に移動してるから、要素までの距離は140pxなので、「140px / 200px = 0.7」。現在の大きさから「0.7」倍すれば元の見ための大きさに戻るということです。
transform
の値にscale()
を追記。
figure img {
-webkit-transform: translateZ(60px) scale(0.7);
transform: translateZ(60px) scale(0.7);
}
他の要素も同じ要領で、元の見た目の大きさになるように調整すれば、できあがりー:D!
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 手前にパララックス</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述と同じ --> </body> </html>
/* :::::: contents :::::: */ /* コンテンツ部分は「画面の端からニュッと出るメニュー」の項参照 */ /* :::::: parallax :::::: */ html, body, #wrapper { height: 100%; } #wrapper { overflow: auto; -webkit-perspective: 200px; perspective: 200px; } nav { -webkit-transform: translateY(50px) translateZ(50px) scale(.75); transform: translateY(50px) translateZ(50px) scale(.75); } h2 { -webkit-transform: translateZ(20px) scale(.9); transform: translateZ(20px) scale(.9); } figure img { -webkit-transform: translateZ(60px) scale(.7); transform: translateZ(60px) scale(.7); } figure figcaption a { -webkit-transform: translateZ(40px) scale(.8); transform: translateZ(40px) scale(.8); }
奥にパララックス
手前に配置した要素は通常よりも早くスクロールしてましたが、奥に配置すれば、通常よりも遅くスクロールする事になります。
下のサンプルは、各要素が、上のサンプルとは逆順になるよう配置してます。
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 奥にパララックス</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述と同じ --> </body> </html>
/* :::::: contents :::::: */ /* コンテンツ部分は「画面の端からニュッと出るメニュー」の項参照 */ /* :::::: parallax :::::: */ html, body, #wrapper { height: 100%; } #wrapper { overflow: auto; -webkit-perspective: 200px; perspective: 200px; } nav { -webkit-transform: translateY(-50px) translateZ(-50px) scale(1.25); transform: translateY(-50px) translateZ(-50px) scale(1.25); } h2 { -webkit-transform: translateZ(-20px) scale(1.1); transform: translateZ(-20px) scale(1.1); } figure img { position: relative; z-index: -1; -webkit-transform: translateZ(-60px) scale(1.3); transform: translateZ(-60px) scale(1.3); } figure figcaption a { z-index: -1; -webkit-transform: translateZ(-40px) scale(1.2); transform: translateZ(-40px) scale(1.2); }
横スクロールバーが出ちゃいますね…。
translateX()
で手前に移動させて大きく見える時には、要素自体の大きさは変わらないので、スクロールバーは出ませんでしたが、scale()
で拡大した時には、要素自体が大きくなるため、#wrapper
からハミ出た分スクロールバーが出ちゃうんですね。
ここでは#wrapper
にoverflow-y: hidden
と指定して、横スクロールバーだけ出ないようにしました;P。
※該当CSSは13行め
- HTML
- CSS
- PREVIEW
- 別窓で開く
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>CSS Animation - 奥にパララックス</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="stylesheet" href="../css/normalize.min.css"> <link rel="stylesheet" href="../css/sample.css"> </head> <body> <!-- HTMLは前述と同じ --> </body> </html>
/* :::::: contents :::::: */ /* コンテンツ部分は「画面の端からニュッと出るメニュー」の項参照 */ /* :::::: parallax :::::: */ html, body, #wrapper { height: 100%; } #wrapper { overflow: auto; overflow-x: hidden; -webkit-perspective: 200px; perspective: 200px; } nav { -webkit-transform: translateY(-50px) translateZ(-50px) scale(1.25); transform: translateY(-50px) translateZ(-50px) scale(1.25); } h2 { -webkit-transform: translateZ(-20px) scale(1.1); transform: translateZ(-20px) scale(1.1); } figure img { position: relative; z-index: -1; -webkit-transform: translateZ(-60px) scale(1.3); transform: translateZ(-60px) scale(1.3); } figure figcaption a { z-index: -1; -webkit-transform: translateZ(-40px) scale(1.2); transform: translateZ(-40px) scale(1.2); }
で、できあがり!
あとがき
記事を書いてる最中にもいろいろ新たな発見とかがあって紆余曲折しながらすごくすごく長くなっちゃいましたが、なんとかキリが着けれてよかったです;D(Chromeは次のバージョンアップでtransform
にベンダープレフィックス要らなくなるみたいだし!)。
たぶん今後もっとよりよい書き方に気付いたり、新しい技術が出てくると思うので、どんどん更新していきたいです。
最後に、動くCSSを使ってサイトを作ってみましたー:D。
記事で紹介したCSSをいろいろ盛り込んでますので、ぜひ覗いて行ってくださいな。
以上、動くCSSのためのメモでしたー。
最後まで読んでいただきありがとうございました!
Comment & Pingback