CSS3アニメーションでつくるインターフェイス表現

第2回アコーディオンメニューのアニメーション

今回のお題はサンプル1のアコーディオンメニューだ。マウスポインタをメニュー項目に重ねると、サブメニューが広がる。また、サブメニュー項目は、マウスポインタの動きに応じてハイライトする。⁠アコーディオンメニュー」をネットで検索すると、jQueryを使った作例が多くリストされるだろう。だが、JavaScriptは使わず、CSS3だけでもアコーディオンメニューの基本的な動きはつくれる。

サンプル1 CSS3:Accordion menu by rollover

メニューのもとになる静的スタイル

まず、<body>要素に書くコードの構成だ。アコーディオンメニューは、つぎのようにclass属性が"menu"の<ul>要素でリストとして組み立てる。メニュー項目をclass属性"item"の<li>要素として、サブメニューはその中にさらに<ul>要素を入れ子にした。サブメニュー項目も<li>要素で、メニュー項目も含め、テキストは子の<a>要素に加えた。そして、アコーディオンメニューの<ul>要素全体を、class属性"container"の<div>要素で包んだ。

<div id="container">
<ul class="menu">
    <li class="item">
        <a id="menu01"><span>メニュー項目1</span></a>
        <ul>
            <li><a href="#">サブメニュー項目1</a></li>
            <li><a href="#">サブメニュー項目2</a></li>
            <!-- サブメニュー項目の<li>要素続く -->
        </ul>
    </li>
    <li class="item">
        <a id="menu02"><span>メニュー項目2</span></a>
        <ul>
            <!-- サブメニュー項目の<li>要素続く -->
        </ul>
    </li>
    <!-- メニュー項目の<li>要素続く -->
</ul>
</div>

メニューの項目のテキストやリンクを加えたのがつぎのコードだ。メニュー項目はふたつ、サプメニュー項目はそれぞれ3つとふたつにした。最後のclass属性"item"の<li>要素は、アコーディオンメニューの下端の縁にするので、メニュー項目ではない(中にid属性"bottom"の<span>要素を加えた⁠⁠。

<div id="container">
<ul class="menu">
    <li class="item">
        <a id="menu01"><span>リファレンス</span></a>
        <ul>
            <li><a href="https://developer.mozilla.org/docs/Web/JavaScript/Reference" target="_blank">JavaScriptリファレンス</a></li>
            <li><a href="https://developer.mozilla.org/docs/Web/CSS/Reference" target="_blank">CSSリファレンス</a></li>
            <li><a href="http://semooh.jp/jquery/" target="_blank">jQueryリファレンス</a></li>
        </ul>
    </li>
    <li class="item">
        <a id="menu02"><span>gihyo.jp</span></a>
        <ul>
            <li><a href="http://gihyo.jp/design/serial/01/createjs" target="_blank">CreateJS</a></li>
            <li><a href="http://gihyo.jp/design/serial/01/away3d-typescript" target="_blank">Away3D TypeScript</a></li>
        </ul>
    </li>
    <li class="item">
        <span id="bottom"></span>
    </li>
</ul>
</div>

この<body>要素の記述に対して、つぎのような<style>要素を加える。今のところ、アコーディオンメニューは開いたまま動かず、マウスポインタを重ねた項目のハイライトといったアニメーションもない図1⁠。なお、CSSにベンダープレフィックスを付けなくて済むように、<script>要素で-prefix-freeを読み込んだ(第1回のベンダープレフィックスと-prefix-freeの項参照⁠⁠。

<script src="lib/prefixfree.min.js"></script>
<style>
* {
    margin: 0;
    padding: 0;
}
body {
    font: 14px sans-serif;
}
#container {
    margin: 50px auto 0;
    width: 200px;
}
.menu {
    width: 200px;
    list-style: none;
    border: 1px solid darkgray;
    background: silver;
}
.item {
    overflow: hidden;
    cursor: pointer;
}
.item a span {
    display:block;
    padding:10px 10px 10px 20px;
    color: black;
}
.item ul li a {
    display: block;
    padding-left: 20px;
    line-height: 30px;
    text-decoration: none;
    font-size: 14px;
    background: white;
    color: darkslategray;
}
#bottom {
    display:block;
    padding:10px 10px 10px 20px;
    cursor: default;
}
</style>
図1 アコーディオンメニューのもととなるスタイル
図1 アコーディオンメニューのもととなるスタイル

メニューに角の丸みと影を加える

アコーディオンメニューを動かす前に、もう少し飾りつけよう。アコーディオンメニューclass属性"menu")<ul>要素の4つ角は丸めて、ドロップシャドウを加える図2⁠。プロパティborder-radiusに角丸の半径、box-shadowには影の水平・垂直のずれとぼけ幅および色をつぎのように定めた(第1回のボタンの角に丸みを加えるおよび影でボタンを立体的に見せるの項を参照⁠⁠。

.menu {

    border-radius: 20px;

    box-shadow: 0px 4px 10px darkgray;
}
図2 アコーディオンメニューに角の丸みと影を加えた
図2 アコーディオンメニューに角の丸みと影を加えた

さらに、アコーディオンメニューの背景色は線形のグラデーションにする。この場合にカラーを定めるのが、linear-gradient()関数だ。引数には、つぎのようにグラデーションの向きと、始まりおよび終わりの色を与える。

linear-gradient(to 方向, 始まりの色, 終わりの色)

アコーディオンメニューclass属性"menu")<ul>要素のbackgroundプロパティは、つぎのように色をlinear-gradient()関数に書き替えて、背景色は上から下へのグレーのグラデーションにした図3⁠。

.menu {

    background: linear-gradient(to bottom, whitesmoke, silver)/* silver */;

}
図3 アコーディオンメニューの背景色にグラデーションが掛かった
図3 アコーディオンメニューの背景色にグラデーションが掛かった

メニューの開け閉じの動きを加える

いよいよ、アコーディオンメニューに開け閉じの動きを加えよう。縦に伸び縮みさせるので、つぎのようにサブメニュー項目の<a>要素に対してheightプロパティを用いる。初めはつぶしておき(0⁠⁠、メニュー項目class属性"item")にマウスポインタが重なったら:hover擬似クラス)高さを戻せばよい。そして、transitionプロパティで、アコーディオンの名前通りの滑らかなアニメーションとした(第1回のボタンに滑らかなアニメーションを定めるの項参照⁠⁠。

.item ul li a {

    height: 0;

    transition: 0.5s;
}
.item:hover ul li a {
    height: 30px;
}

transitionプロパティに「タイミング関数」timing-functionを定めると、アニメーションの動き方が変えられる。簡単に使うには、予め備わっている7つのキーワードから選べばよい。デフォルト値は、始めは加速して終わりに減速するease図4左⁠⁠。MDN「timing-function」一般的なタイミング関数のキーワードの項に7つのキーワードとそのグラフが掲げられているので、興味があれば試してみるとよいだろう。このお題ではeaseよりもう少しめりはりの効いたease-in-outを加える図4右⁠⁠。

.item ul li a {

    transition: 0.5s ease-in-out;
}
図4 タイミング関数のeaseとease-in-out
ease(デフォルト)
図4 ease(デフォルト)

ease-in-out
図4 ease-in-out

この図Mozilla Contributorsによるもので、CC-BY-SA 2.5のもとで利用が許諾されています。

メニュー項目の間に区切り線を入れる

アコーディオンメニューを閉じたとき、項目の間の区切りがわからないのは少し気になる図5⁠。そこで、メニュー項目class属性"item")border-topプロパティで、以下のコードのように区切り線を入れることにしよう。

図5 メニュー項目の間に区切りがない
図5 メニュー項目の間に区切りがない
.item {

    border-top: 1px solid white;

}

確かめてみると、メニュー項目の間だけでなく、アコーディオンメニュー上端にも線が入ってしまう図6⁠。この線は余計だ。そこで以下のコードのように、プルダウンメニューclass属性"menu")の項目class属性"item")のうち最初の<li>要素を:first-child擬似クラスで指定して、その線は消すnoneこととした。これで、アコーディオンメニューの項目の間にだけ区切り線が入った図7⁠。

図6 アコーディオンメニュー上端の線が余計
図6 アコーディオンメニュー上端の線が余計
.menu li.item:first-child {
    border-top: none;
}
図7 アコーディオンメニューの項目の間にだけ区切り線が入った
図7 アコーディオンメニューの項目の間にだけ区切り線が入った

サブメニュー項目にポインタを重ねたときハイライトさせる

仕上げに、サブメニュー項目にマウスポインタを重ねたとき、背景色を変えてハイライトさせよう。サブメニュー項目の<a>要素の:hover擬似クラスで、つぎのようにbackgroundプロパティのカラーを定めた。また、サブメニュー項目の文字色は濃いグレーにしてあったので、そのカラーも黒に変えている。これで、マウスポインタを重ねたサブメニュー項目がハイライトする図8⁠。これで、アコーディオンメニューのアニメーションはでき上がった。CSSの定めは以下のコード1にまとめたとおりだ。

.item ul li a:hover {
    background: lightsteelblue;
    color: black;
}
図8 アコーディオンメニューのサブメニュー項目にマウスポインタを重ねるとハイライトする
図8 アコーディオンメニューのサブメニュー項目にマウスポインタを重ねるとハイライトする
コード1 アコーディオンメニューのアニメーション
* {
    margin: 0;
    padding: 0;
}
body {
    font: 14px sans-serif;
}
#container {
    margin: 50px auto 0;
    width: 200px;
}
.menu {
    width: 200px;
    list-style: none;
    border-radius: 20px;
    border: 1px solid darkgray;
    background: linear-gradient(to bottom, whitesmoke, silver);
    box-shadow: 0px 4px 10px darkgray;
}
.item {
    overflow: hidden;
    border-top: 1px solid white;
    cursor: pointer;
}
.menu li.item:first-child {
    border-top: none;
}
.item a span {
    display:block;
    padding:10px 10px 10px 20px;
    color: black;
}
.item ul li a {
    display: block;
    padding-left: 20px;
    line-height: 30px;
    height: 0;
    text-decoration: none;
    font-size: 14px;
    background: white;
    color: darkslategray;
    transition: 0.5s ease-in-out;
}
.item:hover ul li a {
    height: 30px;
}
.item ul li a:hover {
    background: lightsteelblue;
    color: black;
}
#bottom {
    display:block;
    padding:10px 10px 10px 20px;
    cursor: default;
}

おすすめ記事

記事・ニュース一覧