マウスオーバーエフェクト

ボタンや画像にカーソルを乗せた時の反応って大事ですよね。リンクするエリアにカーソルを合わせた時に、カーソルが指のアイコンに変わったり、テキストの色が変わったりすれば、カーソルが乗ったという事が認識しやすくなります:)
それに加えて、ちょっとしたエフェクトがあれば、温度や感触や、世界観まで伝えられるかも。

ふわっとする

下のサンプルみたく、:hoverを使ってスタイルを指定しておけば、カーソルが乗った時に、そのスタイルが適用されます。
けどそれだけだと、カチッと切り替わるだけ。

a:hover {
	color: #dc6688;
	text-decoration: inherit;
}

サイトの雰囲気にもよるけれど、もちょっとだけ柔らかい印象にしたいなって時には、ふわっとするとよいかもです。文字色の変わり方と、下線の消え方滑らかにすることで、ふわっとした感じになります:)
この切り替わりを滑らかにするにはtransitionプロパティを使います。
以下のように書くと、a要素でのcolorプロパティの値の変化の仕方を指定できます。下ソースコードは「0.3秒かけていい感じで切り替わる」という指定。

a {
	transition: color 0.3s ease 0s;
}

これで文字色だけ、ふわっと変化するようになりました。;D

transitionプロパティの値は左から順に、property(プロパティ名)duration(速度)timing-function(緩急具合)delay(遅延時間)を表してて、上のソースコードを個別に指定するなら、以下のようにも書けます。

a {
	transition-property: color;
	transition-duration: 0.3s;
	transition-timing-function: ease;
	transition-delay: 0s;
}

それぞれのプロパティの初期値を省略して、下記だけでもよいです:)

a {
	transition: color 0.3s;
}

それから、値が1未満の小数なら、最初の0端折はしょることができるので、以下のようにも書けます;)

a {
	transition: color .3s;
}

さらに下線もゆっくり消えてゆくようにするには、transitionプロパティのcolorの指定の後に、下ソースコードのようにカンマ区切りで、text-decorationの指定を追記します。

a {
	transition: color .3s, text-decoration .3s;
}

ただし、これだけじゃ下のサンプルのようにまだカチッとしたままです。

これは、a:hoverの指定で、下線をtext-decoration: inheritと指定して消しているから。
inheritインハーリット継承するという意味で、a要素の親要素(つまりp要素)のtext-decorationプロパティの値を継承する、という指定になります。p要素のtext-decorationの値は初期値のままなので、そもそも下線を表示しない指定になっちゃってるってわけX)

p {
	text-decoration-color: currentcolor;
	text-decoration-line: none;
	text-decoration-style: solid;
	text-decoration-thickness: auto;
}
text-decorationプロパティの初期値

transitionプロパティは、値の変化をスムーズにすることができるプロパティなので、その効果を発揮できるのは、プロパティの値が数値の時(数値で表せる時)なのですねー。
初期値にするのではなくて、下線の色だけを透明にすれば、transitionプロパティの効果を発揮できるはずです。
下線の色を透明するにはtext-decoration-colorの値に、透明色を表す値transparentを指定します。

a:hover {
	text-decoration-color: transparent;
}

下線もふわっとなりました;D

画像ボタンもふわっする

画像ボタンやバナーの場合は、img要素を包むa要素の背景画像に、マウスオーバー時の画像を指定して、img要素のopacityを徐々に変化させれば、ふわっと切り替わったように見えます:)

画像ボタンの構造
.bnr {
	background: url(hov.png) center / cover no-repeat;
}
.bnr img {
	transition: opacity .3s;
}
.bnr:hover img {
	opacity: 0;
}

ふわっとカチッする

CSSで作ったボタンなら、backgroundbox-shadowなど、いじれるプロパティがいっぱいあるので、ふわっとさせ甲斐がありますねー!まとめてtransitionを指定すれば、より魅力的なアニメーションが表現できます。

.btn {
	︙
	color: ghostwhite;
	background: #86c0de;
	box-shadow: 0 6px 0 hsl(200deg 37% 50%), 0 12px 0 rgba(0,0,0,.2);
	transition: color .3s, background .3s, box-shadow .3s, transform .3s;
}

上の例では、ボタンの地色background、文字色color、ボタン側面の色と影の色box-shadow、ボタンの位置transformの4つのプロパティを、徐々に変化させています。

.btn:hover {
	color: white;
	background: hsl(200deg 62% 75%);
	box-shadow: 0 3px 0 hsl(200deg 47% 60%), 0 6px 0 rgba(0,0,0,.2);
	transform: translateY(3px);
}
ボタンの仕組み

また、カーソルを乗せた時にはゆったり動いてますが、ボタンを押下した時にはちょっと早めに動くようにしてます。

.btn:active {
	︙
	transition-duration: .1s;
}

.btnに指定したtransitionの値を、:activeの時にはdurationの値だけ.1s上書きしてるんですねー。これで、ボタンを押下した時だけ0.1秒で変化して、それ以外の時には0.3秒で変化するようになります。

ぽよんっとする

カーソルを乗せた時にボタンをぽよんっと、柔らかそうなアニメーションをつけたいって時には、transitionプロパティだけではちょっと難しいです。
transitionプロパティは2点間の変化をスムーズにしてくれるだけなので、複雑なアニメーションには向いていないんですね。

ぽよんっと柔らかそうなボタン

ちょっと込み入ったアニメーションを表現したい場合にはanimationプロパティを使うのが良いです。以下のように指定します。

.btn:hover {
	︙
	animation: poyo .6s;
}

animationプロパティには、name(アニメーション名)duration(速度)timing-function(緩急具合)delay(遅延時間)iteration-count(反復回数)direction(方向)play-state(再生状態)fill-mode(充填モード)という8つの値が指定できます。

上のサンプルの指定を全プロパティ分指定すると以下のようになります。poyo.6s以外はぜんぶ初期値なので端折ってたわけですねー:D

p {
	animation: poyo .6s ease 0s 1 normal running none;
}

ぜんぶ書く場合、プロパティを書く順番は自由ですけれど、ひとつだけ、durationdelayの順番だけは「durationが先」と決まってるので注意です。
※上ソースコードの場合なら、0秒待ってから0.6秒かけてアニメーションする指定になります。

ただし、この指定だけではアニメーションしません。別途@keyframes規則という、キーフレームを定義するための特別な構文を使って、アニメーションを用意する必要があるんです。用意して初めて、animationプロパティで使えるようになるってことなんですねー:o
ここでは、以下のように定義しました。

@keyframes poyo {
	from, to { transform: none; }
	10% { transform: scale(1.2); }
	40% { transform: scale(.9); }
	60% { transform: scale(1.04); }
	80% { transform: scale(.98); }
}

カーソルを乗せるとぽよんっとしますね!
よぉ〜く見てみると@keyframesで定義した通りに動いてます。
カーソルを乗せてすぐ(0.06秒後)1.2倍に大きくなったあと、0.9倍にちょっと小さくなって、また1.05倍に大きくなって、その後0.98倍に微妙に小さくなって、最後に元の大きさに戻ります。

ぽよんっの動き

クリックした時もぽよんっする

こうなると、カーソルを押下した時にもぽよんっをつけたくなりますね!
@keyframes規則pushというキーフレームを定義して、以下のように指定してみました。

.btn:active {
	︙
	animation: push .6s;
}
@keyframes push {
	from, to { transform: none; }
	10% { transform: scale(.8); }
	40% { transform: scale(1.1); }
	60% { transform: scale(.96); }
	80% { transform: scale(1.02); }
}

柔らかそうXD
けど、ぽよんっの最中でカーソルを外すと、ピクッピクッてなんだか気持ち悪いですね…⁑O

ぽよんっを止めない

アニメーションが終わるまでアニメーションを始めないようにするのは、CSSだけでは難しくて、JavaScriptを使って制御しないといけません。
ここでは、以下のようなJavaScriptを用意しました。

document.addEventListener('DOMContentLoaded', () => {
	const btn = document.querySelector('.btn');
	btn.addEventListener('mouseenter', e => {
		e.target.classList.add('is-poyo');
	});
	btn.addEventListener('mouseup', e => {
		e.target.classList.add('is-poyo');
	});
	btn.addEventListener('animationend', e => {
		e.target.classList.remove('is-poyo');
	});
});

3〜5行めで、ボタンにカーソルが乗った時mouseenterに、is-poyoというclassを付ける、ということをしています。それから、6〜8行めで、カーソルを押下し終わった時mouseupにも、is-poyoというclassを付けています。
そして、9〜11行めで、アニメーションが終わった時animationendに、is-poyoというclassを外す、ということをしています。

CSSで、:hoverに適用していたアニメーションの指定を、このis-poyoというclassが付いた時に適用されるように、指定し直します。

.btn.is-poyo {
	animation: poyo .6s;
}

アニメーションの途中でカーソルを外しても、ピクッピクッとしなくなりましたね;D

アニメーションのイージングについて

animation-timing-functionプロパティで指定した「アニメーションの仕方」は、アニメーション全体を通してではなく、@keyframesで定義したフレームごとに適用されます。
下サンプルでは、fromtoのみ、from50%toの3時点を、from10%30%60%toの5時点を、それぞれ定義し、イージングはcubic-bezier(.16,1,.3,1)easeOutExpoを指定してます。
「最初は速くてだんだん遅くなる」というイージングが、フレームごとに適用されてますね。

パーセント指定した時点がフレームの節目になる

上のサンプルは「左から右へ移動する」というアニメーションしか定義してないのに、右から左へもアニメーションして戻ってます。これは、animation-directionalternateを指定してるため、偶数回めのアニメーションが逆再生されてるからなんです。
左から右へ移動する時は「最初は速くてだんだん遅くなる」という風にアニメーションしてますが、戻る時(右から左へ移動する時)は「最初が遅くてだんだん速くなる」という風に、イージングの仕方も逆になってるのがわかります。

戻る時はイージングも逆方向になる

animation-directionプロパティの値をnormalにしてみました。偶数回めも左から右へ移動するアニメーションが再生されるので、繋がりがなくて不自然ですね。。

下のサンプルならnormalで繰り返しても割と不自然じゃないです:)

normalでやる時は、開始と完了地点が見えないようにするか、ボタンの時みたくちゃんともとの状態に戻るようにした方がよさげです。
場面によって使い分けが必要ということですね;)

アニメーションの前後に適用されるスタイルについて

下のサンプルでは、背景色がグレーのp要素に、カーソルを乗せると1秒かけて水色から赤色にグラデーションするgradationというアニメーションを適用しています。

p {
	background: #eee;
}
p:hover {
	animation: gradation 1s;
}
@keyframes gradation {
	0% { background: #86c0de; }
	100% { background: #dc6688; }
}

4つのボタンをクリックすると、animation-fill-modeプロパティの値をそれぞれ、noneforwardsbackwardsbothに切り替えることができるので、それぞれの挙動を確認してみてください;)
下の段の「1秒後にグラデーションする要素」の方が、それぞれの値の特徴が顕著に現れてますね。

none
カーソルを乗せても何も変化せず、1秒後にようやく水色から赤色へ変化し、アニメーション後すぐグレーに戻る。
forwards
1秒間は何も変化せず、1秒後にようやく水色から赤色へ変化し、そのあとはカーソルを外すまで赤色のまま。
backwards
カーソルを乗せた後すぐに水色に変わり、1秒後にグラデーションを開始し、アニメーション後すぐグレーに戻る。
both
すぐに水色に変わり、1秒後にグラデーションを開始し、カーソルを外すまで赤色のまま。

animation-fill-modeの値の役割をまとめてみると下図のようになります!
使いどころに合わせて、効率的に使いたいですねー;D

animation-fill-modeのまとめ

詳細はあとから表示する

最初は表示されてないんだけど、サムネイル画像の上にカーソルを乗せると、その画像に関する情報が表示されるような、そんなUIよくありますね。ごちゃごちゃした情報は見たい時だけ、最初の見た目が煩雑にならずにシンプルなデザインにできるので、フラットなデザインとも相性がいいんですよね:)
下のサンプルみたいなののことです:D

そんなわけで、上のサンプルの左のやつから順に仕組みメモです。それぞれHTMLの構造は以下のようになってます。
li要素の中に、figure要素(画像)と、dl要素(詳細情報)が並んでる状態ですね。

<ul class="details">
	<li class="type1">
		<figure class="image"><img src="pain1.png" alt="" width="500" height="400"></figure>
		<dl class="text">
			<dt>カンパーニュ</dt>
			<dd>外はパリッと香ばしく、中はしっとりもちっとした食感。田舎パンらしい素朴な味わいです。</dd>
			<dd class="price">¥300</dd>
		</dl>
	</li>
	︙
</ul>

上記のHTMLを元に、詳細は後から表示するためのCSSの指定方法を紹介してゆきます!

下から出る詳細

詳しい情報は画像の下に隠しておいて、カーソルが乗ったら下からスッとスライドする仕組み。

普段は画像の下に隠れてる

まずはli要素position: relativeを指定。これで、li要素が、その子要素を絶対配置するときの基準になります。dl要素position: absoluteを指定しinset: 0とすれば、figure要素の上に重なった状態で配置されます。

li {
	position: relative;
}
dl {
	position: absolute;
	inset: 0;
	margin: 0;
	padding: 16px 24px;
	border-radius: 8px;
	color: white;
	background: rgba(220,102,136,.9);
}

dl要素の上下のスライドはtransformプロパティtranslateで移動させています。
最初の状態では、dl要素にtranslateY(100%)と指定。これで、その要素の高さ分、下方向に移動します。カーソルが乗ったときはnoneとして、元の位置に戻します。

.type1 {
	overflow: hidden;
}
.type1 dl {
	opacity: 0;
	transform: translateY(100%);
	transition: opacity .6s, transform .6s cubic-bezier(0.215, 0.61, 0.355, 1);
}
.type1:hover dl {
	opacity: 1;
	transform: none;
}

けど、カーソルに乗った時の指定って、opacityプロパティもtransformプロパティも初期値に戻すだけなので、なんだか冗長です…。こんな時は、:not()(否定擬似クラス)を使うとよいです。通常状態とカーソルが乗った時の両方を指定するのでなくて、カーソルが乗っていない時だけ指定するってわけですね;)

.type1 dl {
	transition: opacity .6s, transform .6s cubic-bezier(0.215, 0.61, 0.355, 1);
}
.type1:not(:hover) dl {
	opacity: 0;
	transform: translateY(100%);
}

くるんと裏返る

まるで一枚のカードみたく、写真の裏面に詳細情報が載ってるような表現です。

上述と同じように、position: absoluteでfigure要素とdl要素を重ねて配置。
最初の状態では、dl要素は裏返ってる状態なので、rotateX()を使ってX軸を中心に上下に回転させておき、カーソルが乗った時に、figure要素とdl要素を同時に+180°回転させてます。

.type2 dl {
	background: #cd5c5c;
	transform: rotateX(-180deg);
}
.type2:hover img {
	transform: rotateX(180deg);
}
.type2:hover dl {
	transform: none;
}

カーソルが乗った時に<img><dl>を、同じタイミングで回転させる事で、一枚のカードのように見せてるんですねー。

普段は画像の裏側に隠れてる

裏返る演出で大事なのがbackface-visibilityというプロパティ。このプロパティにhiddenと指定した要素は、裏返った時に不可視状態になります。

.type2 .image,
.type2 .text {
	-webkit-backface-visibility: hidden;
	backface-visibility: hidden;
}

backface-visibilityで裏側だと判断されるのは、transformプロパティのrotateX()rotateY()で、90°以上回転した時。下のサンプルは、左が「表面の要素のみ」真ん中が「裏面の要素のみ」になってます。表面が裏返ると不可視状態になり、その瞬間に裏面が可視状態になってるのがよくわかりますねー。

この指定がないと下のサンプルのように、裏側も丸見え、というか、裏面が表面の上に乗っちゃってます。

backface-visibilityについて詳しくは下記サイトを参照のこと。
backface-visibility - CSS: カスケーディングスタイルシート | MDN

あと、回転する要素の親要素には、perspectiveプロパティを指定してます。

.type2 {
	perspective: 1000px;
}

perspectiveは、遠近感を指定することができるプロパティ。指定する値は、その要素を見ている視点の位置を表してて、ここでは、1000px離れた所で見てる感じになります。

100px離れたとこからみてる人と、1000px離れたとこからみてる人

つまり、この値が小さい(近い)ほど遠近感が強く、大きい(遠い)ほど遠近感が緩くなるってことですね:)
この指定がないと、下のサンプルみたく、立体感がなくなって、裏返ったのか縦に縮んだのかわからなくなっちゃいます…。

perspectiveについては下記記事が詳しいです。
HTML5 × CSS3 × jQueryを真面目に勉強 – #10.1 CSS3 Transforms(3D) | Developers.IO(2012.12.27)

左右から背景が出てくる

パネル状の背景が左右から入ってきて、カーテンを閉めるように中央でピッタリ閉じられると、詳細情報がフェードインしてきます。

左右から出てくる背景は、::before疑似要素::after疑似要素で表示させています。疑似要素を使うと、指定した要素の中に、擬似的に別の要素を追加します。
どのように追加するかというと、擬似要素を付けたセレクタの中で、contentプロパティを使って、以下のように書きます。

p::before {
	content: "::beforeの疑似ですよ";
}
p::after {
	content: "::afterの疑似ですよ";
}

HTMLには / とだけ書かれたp要素がひとつ、なのにPREVIEWを見るとテキストが表示されてますね!
こんな感じで、疑似要素とcontentプロパティを使えば、HTMLで書かれた要素とは別に、CSSで新たに要素を作れちゃうんです(擬似的に!):D
::beforeは、指定した要素の開始タグの直後に、::afterは、指定した要素の閉じタグの直前に、要素を追加します。※Chromeで「検証」をしてみても存在を確認できますよ;)

Chromeのデベロッパーツールで存在が確認できる

左右から出てくる背景は、dl要素内に、::before::afterで2つの要素を追加してたわけです(擬似的に!:D

疑似要素で作る疑似背景

他にもいろんなプロパティと組み合わせればもっと面白な演出だってできちゃいます。トリッキー。

下記サイトでいろんなエフェクトが紹介されてます。どれも素敵ですねーXD
Circle Hover Effects with CSS Transitions(2012.8.8)