マウスオーバーエフェクト
![](/css-animation/hover/eyecatch.webp)
ボタンや画像にカーソルを乗せた時の反応って大事ですよね。リンクするエリアにカーソルを合わせた時に、カーソルが指のアイコンに変わったり、テキストの色が変わったりすれば、カーソルが乗ったという事が認識しやすくなります:)。
それに加えて、ちょっとしたエフェクトがあれば、温度や感触や、世界観まで伝えられるかも。
ふわっとする
下のサンプルみたく、: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;
}
transitionプロパティは、値の変化をスムーズにすることができるプロパティなので、その効果を発揮できるのは、プロパティの値が数値の時(数値で表せる時)なのですねー。
初期値にするのではなくて、下線の色だけを透明にすれば、transitionプロパティの効果を発揮できるはずです。
下線の色を透明するにはtext-decoration-color
の値に、透明色を表す値transparent
を指定します。
a:hover {
text-decoration-color: transparent;
}
下線もふわっとなりました;D
画像ボタンもふわっする
画像ボタンやバナーの場合は、img要素を包むa要素の背景画像に、マウスオーバー時の画像を指定して、img要素のopacity
を徐々に変化させれば、ふわっと切り替わったように見えます:)。
![](img/bnr_mechanism.png)
.bnr {
background: url(hov.png) center / cover no-repeat;
}
.bnr img {
transition: opacity .3s;
}
.bnr:hover img {
opacity: 0;
}
ぽよんっとする
カーソルを乗せた時にボタンをぽよんっと、柔らかそうなアニメーションをつけたいって時には、transitionプロパティだけではちょっと難しいです。
transitionプロパティは2点間の変化をスムーズにしてくれるだけなので、複雑なアニメーションには向いていないんですね。
![](img/poyo.png)
ちょっと込み入ったアニメーションを表現したい場合には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;
}
ぜんぶ書く場合、プロパティを書く順番は自由ですけれど、ひとつだけ、duration
とdelay
の順番だけは「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
倍に微妙に小さくなって、最後に元の大きさに戻ります。
![](img/poyo_keyframes.png)
クリックした時もぽよんっする
こうなると、カーソルを押下した時にもぽよんっをつけたくなりますね!
@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
で定義したフレームごとに適用されます。
下サンプルでは、ろはfrom
to
のみ、ぱはfrom
50%
to
の3時点を、んはfrom
10%
30%
60%
to
の5時点を、それぞれ定義し、イージングはcubic-bezier(.16,1,.3,1)
(easeOutExpo)を指定してます。
「最初は速くてだんだん遅くなる」というイージングが、フレームごとに適用されてますね。
![](img/animation_easing.png)
上のサンプルは「左から右へ移動する」というアニメーションしか定義してないのに、右から左へもアニメーションして戻ってます。これは、animation-direction
にalternate
を指定してるため、偶数回めのアニメーションが逆再生されてるからなんです。
左から右へ移動する時は「最初は速くてだんだん遅くなる」という風にアニメーションしてますが、戻る時(右から左へ移動する時)は「最初が遅くてだんだん速くなる」という風に、イージングの仕方も逆になってるのがわかります。
![](img/easing_reverse.png)
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プロパティの値をそれぞれ、none
、forwards
、backwards
、both
に切り替えることができるので、それぞれの挙動を確認してみてください;)。
下の段の「1秒後にグラデーションする要素」の方が、それぞれの値の特徴が顕著に現れてますね。
none
- カーソルを乗せても何も変化せず、1秒後にようやく水色から赤色へ変化し、アニメーション後すぐグレーに戻る。
forwards
- 1秒間は何も変化せず、1秒後にようやく水色から赤色へ変化し、そのあとはカーソルを外すまで赤色のまま。
backwards
- カーソルを乗せた後すぐに水色に変わり、1秒後にグラデーションを開始し、アニメーション後すぐグレーに戻る。
both
- すぐに水色に変わり、1秒後にグラデーションを開始し、カーソルを外すまで赤色のまま。
animation-fill-mode
の値の役割をまとめてみると下図のようになります!
使いどころに合わせて、効率的に使いたいですねー;D。
![](img/fill-mode.png)
クリック(タップ)するとぽよんっするボタンのアニメーションサンプルです。
動くソースコードが載ってるのでコピペしてみてくださいね。;D
ぽよん。 - Lopan.jp
詳細はあとから表示する
最初は表示されてないんだけど、サムネイル画像の上にカーソルを乗せると、その画像に関する情報が表示されるような、そんな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の指定方法を紹介してゆきます!
下から出る詳細
詳しい情報は画像の下に隠しておいて、カーソルが乗ったら下からスッとスライドする仕組み。
![](img/details_mechanism.png)
まずは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>
を、同じタイミングで回転させる事で、一枚のカードのように見せてるんですねー。
![](img/rotate_mechanism.png)
裏返る演出で大事なのが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離れた所で見てる感じになります。
![](img/details_perspective.webp)
つまり、この値が小さい(近い)ほど遠近感が強く、大きい(遠い)ほど遠近感が緩くなるってことですね:)。
この指定がないと、下のサンプルみたく、立体感がなくなって、裏返ったのか縦に縮んだのかわからなくなっちゃいます…。
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で「検証」をしてみても存在を確認できますよ;)。
![](img/pseudo_element.png)
左右から出てくる背景は、dl要素内に、::before
と::after
で2つの要素を追加してたわけです(擬似的に!:D)。
![](img/pseudo_mechanism.png)
他にもいろんなプロパティと組み合わせればもっと面白な演出だってできちゃいます。トリッキー。
下記サイトでいろんなエフェクトが紹介されてます。どれも素敵ですねーXD!
Circle Hover Effects with CSS Transitions(2012.8.8)
![](../tabs/thumb.webp)
タブコンテンツ