CSS、hoverでアニメーション(ホバーエフェクト)

WEB画面上である要素にポインターを持ってきた時に、アニメーションが起きると、ユーザーに必要なメッセージを届けたり、快適なユーザーエクスペリエンスを実現することが可能となります。

単にカッコいいというだけでなく、メニューからサブメニューの表示、拡大などの他、正解を伏せた学習に活用するなど、使いようによっては機能的に非常に重要な役割を果たさせることもできます。

ここでは、技術的に基礎となるものや実用的なものを10数個集めてみました。

ホバーエフェクトの基本的な使い方と、その応用例を参考にしていただければ幸いです。

まずは10数個のデモを見てみましょう。

ホーバーエフェクトは、通常のCSSアニメーションとは基本的に異なります。

通常のCSSアニメーションはanimationというプロパティと@keyframesの設定で行い、特殊なことをしない限りは、永遠に動き続けるか、一定の時間の後に動き出すという設定の仕方が普通でしょう。

一方、ホバーエフェクトは、その名の通り、マウスオーバー(ホバー)時にのみ反応し、マウスオーバーが終わると元に戻ります。

ホバーエフェクトは、動きを付けたい要素に、

要素名:hover {プロパティ名:値;}

としてCSSのスタイル設定をします。

では、今回のコードを全て見てみましょう。

※今回はCSSの話なので、基本的にはhead内にあるJQueryの読み込みは必要ないのですが、スマホでタッチが反応するためには、touch-punchを含め全て読み込んでおく必要があるようです。

<html>
<head>
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/jqueryui-touch-punch/0.2.3/jquery.ui.touch-punch.min.js'></script>
<style>
    ul {list-style-type: none;}
    li {float: left;}
    table {width: 46vmin; height: 230px; border: 1px #333 solid; border-collapse: collapse; table-layout: fixed;}
    table th {height: 30px; border: 1px #333 solid;}
    table td {height: 200px; border: 1px #333 solid;}
    .box {margin: 5%; width: 90%; height: 90%; box-sizing: border-box;}
    .box1 {background-color: blue; transition: 1s;}
    .box1:hover {opacity: 0;}
    .box2 {background-color: #096; transition: 1s;}
    .box2:hover {height: 0;}
    .box3 {background-color: #845; transition: 1s;}
    .box3:hover {width: 0;}
    .box4 {background: hsl(210 100% 50%); transition: 1s;}
    .box4:hover {background: hsl(0 100% 50%);}
    .box5 {background: #EF3; transition: 1s;}
    .box5:hover {margin-left: 50%; width: 0%; height: 0%;}
    .wrap6 {perspective: 1000;}
    .box6 {background-color: #EAF; transition: 1s;}
    .box6:hover {transform: rotateY(180deg); background-color: #CBF;}
    .wrap7 {position: relative;}
    .box7 {position: absolute; width: 45%; top: 5%; height: 90%; background: #777; transition: 1s;}
    .box7-1 {left: 5%;}
    .box7-2 {right: 5%;}
    .wrap7:hover .box7-1 {width: 0%;}
    .wrap7:hover .box7-2 {width: 0%;}
    
    .wrap8 {position: relative; perspective: 1000;}
    .box8 {position: absolute;  top: 5%; width: 45%; height: 90%; background: #800; transition: 1s;}
    .box8-1 {left: 5%; transform-origin: left;}
    .box8-2 {left: 50%; transform-origin: right;}
    .wrap8:hover .box8-1 {transform: rotateY(90deg);}
    .wrap8:hover .box8-2 {transform: rotateY(-90deg);}   

    .box9 {background: repeating-linear-gradient(45deg, #F77 0, #77F 10%); background-position: 0 0; background-size: 500% 500%; transition: 2s;}
    .box9:hover {background-position: 0% 100%;}

    .box10 {margin: 5%; width: 90%; height: 160px; box-sizing: border-box; border: 0 #0F0 solid; transition: 1s;}
    .box10:hover {border-width: 20px;}

    .box11 {margin-left: 5%; background-image: repeating-conic-gradient(hsl(20, 100%, 70%) 0%,hsl(70, 100%, 100%) 10%); transition: 1s;}
    .box11:hover {width: 0%; height: 0%; border-radius: 50%; margin-left: 50%;}

    .wrap12 {vertical-align: top; padding-top: 10px;}
    .box12 {position: relative; list-style: none;}
    .box12 > li {background: #0C8;}
    .box12 ul {position: absolute; top: 40px; padding-left: 0; list-style: none; color: #FFF; background: #FFF;}
    .box12 li {width: 280px; height: 40px; text-align: center; line-height: 40px; border-top: 2px #FFF solid; transition: 1s;}
    .box12 li:hover ul li {width: 280px; height: 40px; color: #333; background: #0EA;}
    .wrap13 {vertical-align: top; padding-top: 10px;}
    .box13-1 {width: 20%; border: 1px #F55 solid; background: #FFF7F7;}
    .box13-2 {background: #FFF; color: #FFF; display: none;} 
    .box13:hover .box13-2 {display: block; color: #333; background: #EEF; border: 1px #333 solid;}
    .wrap14 {position: relative;}
    .box14-1 {width: 100%; height: 96%;}
    .box14-2 {position: absolute; bottom: 0; left: 30%; font-size: 20px; background-color: #99F; opacity: 0; transition: 1s;}
    .box14:hover .box14-2 {bottom: 20px; opacity: 1;} 
    .wrap15 {position: relative;}
    .box15-1 {position: absolute; left: 5%; top: 5%; width: 20%;}
    .box15-2 {position: absolute; top: 27%; left: 20%; width: 60%; display: none; transition: 1s;}
    .box15:hover .box15-2 {display: block;} 
    .wrap16 {position: relative;}
    .box16 {background: #E08; overflow: hidden;}
    .box16::after {position: absolute; content: ''; top: -50px; width: 50px; height: 300px; left: -30%; transform:rotate(-30deg); opacity: 0.2; background: #FFF; transition: 1s;}
    .box16:hover::after {left: 80%;}
    .wrap17 {position: relative; vertical-align: top; perspective: 800;}
    .box17-1 {position: absolute; left: 5%; top: 5%; width: 90%; height: 30%; text-align: center; font-size: 26px; line-height: 60px;background: #ECF;}
    .box17-2 {position: absolute; left: 5%; top: 5%; width: 90%; height: 30%; color: white; text-align: center; font-size: 26px; line-height: 60px; background: #05F; transform-origin: bottom; transition: 1s;}
    .box17-2:hover {transform: rotateX(-180deg);}
</style>
</head>
<body>
<p style="color: red; font-size: 24px;">それぞれホーバー(またはタッチ)してください</p>
<ul class="mysort">
    <li>
        <table>
          <tr>
           <th>DEMO1</th>
          </tr>
          <tr>
           <td>
             <div class="box box1"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO2</th>
          </tr>
          <tr>
           <td>
              <div class="box box2"><d/iv>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO3</th>
          </tr>
          <tr>
           <td>
              <div class="box box3"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO4</th>
          </tr>
          <tr>
           <td>
              <div class="box box4"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO5</th>
          </tr>
          <tr>
           <td>
               <div class="box box5"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO6</th>
          </tr>
          <tr>
           <td class="wrap6">
               <div class="box box6"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
              <th>DEMO7</th>
          </tr>
          <tr>
           <td class="wrap7">
               <div class="box7 box7-1"></div>
               <div class="box7 box7-2"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO8</th>
          </tr>
          <tr>
           <td class="wrap8">
               <div class="box8 box8-1"></div>
               <div class="box8 box8-2"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO9</th>
          </tr>
          <tr>
           <td>
               <div class="box box9"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO10</th>
          </tr>
          <tr>
           <td>
               <div class="box10"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO11</th>
          </tr>
          <tr>
           <td>
               <div class="box box11"></div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO12</th>
          </tr>
          <tr>
           <td class="wrap12">
               <ul class="box12">
                <li>メニュー
                   <ul>
                      <li>サブメニュー1
                      </li>
                      <li>サブメニュー2
                      </li>
                   </ul>
                </li>
               </ul>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO13</th>
          </tr>
          <tr>
           <td class="wrap13">
               <div class="box13">
                    <div class="box13-1">牽強付会</div>
                    <div class="box13-2">けんきょうふかい: 自分の都合のいいように、強引に理屈をこじつけること。▽「牽強」「付会」はともに、道理に合わないことを無理にこじつけること。「付」は「附」「傅」とも書く。</div>
               </div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO14</th>
          </tr>
          <tr>
           <td class="wrap14">
               <div class="box14">
                    <img class="box14-1" src="tachiaoi.jpg">
                    <div class="box14-2">タチアオイ(立葵)</div>
               </div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO15</th>
          </tr>
          <tr>
           <td class="wrap15">
               <div class="box15">
                    <img class="box15-1" src="watch.jpg">
                    <img class="box15-2" src="watch.jpg">
               </div>
           </td>
          </tr>
        </table>
    </li>
    <li>
        <table>
          <tr>
           <th>DEMO16</th>
          </tr>
          <tr>
           <td class="wrap16">
               <div class="box box16"></div>
           </td>
          </tr>
        </table>
    </li>   
    <li>
        <table>
          <tr>
           <th>DEMO17</th>
          </tr>
          <tr>
           <td class="wrap17">
               <div class="box17-1">獲得・取得・買収</div>
               <div class="box17-2">acquisition</div>
           </td>
          </tr>
        </table>
    </li>  
</ul>
</body>
</html>

DEMO1〜11は、前回ブログ「CSSアニメーション。ボックスのデザイン」のホバーエフェクト版ですので、説明も簡単にさせていただきました。

DEMO1: 透明度opacityを1から0にして消失させる

最も基本的なパターンかもしれません。opacityを1から0に、1秒かけて、ブルーの背景色を透明化しています。

DEMO1,2,3,5,7,8では、下に別の画像を重ねて配置しておくと、それが現れることとなりますので、各自で工夫してみてください。

DEMO2: 高さを0にして閉じる

1秒かけて元の高さが0になるようにしています。

テーブルセル内に配置しているため、中央に向けて閉じることとなります。

DEMO3: 幅を0にして閉じる

元の幅のwidthが0になるようにしています。

初期値が左詰なので、左側に向けて閉じます。

DEMO4:  色を変える

1秒かけて背景色を変更しています。ここではhsl方式で色の指定をしました。二色目、三色目といくつかの色に変わるようにしたかったのですが、通常のアニメーションと異なり、そのような変化は難しいようです。もし、ご存知の方がありましたら、コメントに書き込んでいただければありがたいです。

DEMO5: 中心に向けて閉じる

幅と高さの両方をに変化させています。

前回CSSアニメーションと同様に、左右方向も中央になるように、margin-leftも併せて変化させています。

DEMO6: 裏返るように回転させる

transform: rotateY(180deg)を使って裏返しています。

DEMO7: 両側に開ける

二つのボックスを用意し、それぞれの幅を0に変化させています。

指定が容易なように、先ほどのようなmargin-leftは使わず、position: absoluteで絶対位置を指定しています。

absoluteを指定するには、親要素にrelativeを指定しておく必要があります。

ホバーによって二つの要素を同時に動かしたい時は、ここにあるように、親要素に対して、親要素:hoverとし、それを二つ書いて、その後に動かしたい要素を書くと、複数の要素に対して、エフェクトを効かせることができます。

DEMO8: 観音開きにする

今度は左右のそれぞれの要素を90回転させます。

奥行きが出るように、親要素にperspectiveを指定しています。

DEMO9:  縞模様を移動させる

repeating-liner-gradientを使って縞模様をあらかじめ作成しておき、background-positionを変えることで動きをつけています。

DEMO10:  境界線を付ける

border-widthで何もないボックスに枠をつけています。

ボックスにbox-sizing: border-boxを指定していることが重要となります。

初期値のcontent-boxのままだと、境界線はボックスの外側について拡大してしまいますので、この指定が重要になります。

なお、height : 90%のままでは、高さが少し縮むので、height: 160pxとして上書きしています。

DEMO11:  放射状グラデーションを背景とするボックスを中心に向けて閉じる

放射状グラデーションの背景は、repeating-conic-gradientを用いています。

その背景に対して、ボックスを中央に向けて縮小しています。

その際、border-radiusを初期値の0(つまり角丸が全くない状態)から50%

に変化させて、最終的には楕円になるようにしています。

DEMO12: サブメニューを表示する

グローバルメニュー表示などに大変便利な方法だと思います。

ホバー時のみ表示されるので、他の表示の邪魔にならないというメリットがあります。

ulとliタグを組み合わせたリスト表示としています。

ここでは一つのメニューしか表示していませんが、この方式だと、横向きに複数のメニューを並べることも簡単になります。

ここでは、CSSのセレクタの指定方法として、普段あまり使わないものが出てきます。

スペースで区切る場合は要素内に含まれる要素、「>」を使うと直下の子要素を指すこととなります。

また、「要素:hover ul li」のようにhoverの下に要素を限定できるので、このような使い方にも慣れたいものです。

実際のグローバルメニューでは、ここに書いてあるだけでなく、aタグでリンクを埋め込む必要がありますので、各自で追加してみてください。なかなかややこしいですが、わからない方は、ネットで検索して調べてみてください。

DEMO13:  テキストの意味を解説するボックスを表示する

わからない単語などに、ホバーをすると解説が出てくるような仕組みは便利です。

ここでは、「牽強付会」という難しい四字熟語の解説が出るようにしました。

opacity:0からopacity:1に時間をかけてゆっくり変化させるということもできますが、それをすると、「牽強付会」の文字の上だけでなく、見えていない解説のところにマウスオーバーしても反応してしまうという欠点が出てしまいます。

そこで、ここでは、一瞬にして反応してしまいますが、display: noneをdisplay: blockに変化させる方式を採用しました。

この場合、display: noneは存在しないことになるので、解説が現れる領域にマウスオーバーしても反応しなくなります。

DEMO14: 写真に説明を浮かび上がらせる

たくさん写真を並べておいて、何の写真であるか知りたい場合にだけ、マウスオーバーで名前や説明が出るようにしたいということがあるかもしれません。

ここでは、それを実現してみました。

重ね書きとなりますので、親要素にposition: relativeを指定し、子要素にposition: absoluteを指定して、配置を決めましょう。

ここではbottom: 0からbottom: 20pxに浮き上がるようにしています。

また透明度opacityも1に上げて背景色をつけました。

DEMO15: 細かな画像の拡大図を表示する

商品販売サイトなどで、商品の詳細な画像を表示する際などに、この機能を活用すると便利です。

これはあらかじめ二つの大きさで画像を用意しておいて、ホバー時に、二つ目の拡大図が表示されるようにします。

ここでもDEMO13と同様に、opacityの変化は使わず、displayをnoneからblockに変化させています。

先ほど書いたように、拡大図が現れる領域でマウスオーバーした際に反応しないようにするためです。

DEMO16: 光を走らせる

ここはグラデーションの機能ではなく、擬似要素を使って、それをマウスオーバー時に動かすようにしました。

擬似要素を示す「::after」を使って、あらかじめ光の感じの長方形を枠のすぐ外に斜めに作っておきます。

そして「要素:hover::afrter」のように指定して、擬似要素に指定したCSSスタイルを変更しています。

ここではleftの位置を変更させることで、左から右に光が走るようにしました。

DEMO17:  一枚目を裏返して二枚目を表示させる

コンピュータでは要素を重ね合わせても、見えない下側にもちゃんと文字が表示されていたりするので、そこは便利で面白いです。

ここでは、一枚目の紙を裏返しに取り除くと、下側の表示が見えるようにしています。

上の要素に対して、transform: rotateX(-180deg)で回転させますが、下側を軸として回転させたいので、回転軸をtransform-origin: bottomとして指定しておく必要があります。

まとめ

いかがでしたか。

今回は、最初の11個ほどは、前回のCSSアニメーションをホバーエフェクトに書き換えたものですが、実用的な物もいくつか追加してみました。

動きのある面白いサイトを作るという意味だけでなく、例えば、ボタンのエフェクトがあるとユーザーには確かに反応しているという安心感を与えることができますし、また、メニューや拡大図、言葉の解説など、結構機能的にも重要なことができるようになったりします。

ここでは、わかりやすいように、プロパティの変化は大体一つに絞りましたが、組み合わせたり、開いた下側に画像を入れておくと、もっと面白い動きになります。

また、親要素のマウスオーバーに対して、子要素をいくつも反応させるとさらに面白い動きが実現できるでしょう。

皆さんもWEBサイトに取り入れて、一歩上をいくサイトを作ってみてください。