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

第17回立体的なナビゲーションバーのアニメーション

今回のお題は、ボタンが立体的に並んだナビゲーションバーだサンプル1⁠。マウスポインタを重ねると、ボタンが飛び出す。Navigation Bar by Jan Kaděraのデザインとアニメーションをもとに、わかりやすく組み立て直した。3次元の動きで、ボタンの数も多い。少しやっかいそうに感じたかもしれない。ところが、思いのほかコードはたやすい。

サンプル1 CSS3: 3D style navigation bar

平面的なナビゲーションバー

まずは<head>要素にいくつか仕込みをしておこう。ボタンのアイコンにはFont Awesomeを使うので、つぎのようにCDNを読み込む(第15回のアイコンWebフォントを使う参照⁠⁠。おなじみの-prefix-freeも加える。そして、今回はリセットCSSを用いた。ブラウザによって異なるデフォルトをリセットすることで、表現が揃えられる。広く使われているのは、Eric Meyer氏のCSS(⁠2016年で最もダウンロードされたリセットCSSランキングトップ5⁠。CDNはcdnjsのmeyer-resetから読み込んだ。

<head>

<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">

<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
</head>

HTMLのコードはつぎに示す簡素なつくりだ。<ul>要素class属性"nav-bar")の中にボタンを、要素<li><a>class属性"list-item")の入れ子で加えた。そこにFont Awesomeのアイコンが入っている。

<body>要素
<ul class="nav-bar">
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-bars"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-th-large"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-bar-chart"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-tasks"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-bell"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-archive"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-comment"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-sitemap"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-thumbs-up"></i>
        </a>
    </li>
    <li>
        <a class="list-item" href="#">
            <i class="fa fa-tumblr"></i>
        </a>
    </li>
</ul>

これにつぎのCSSを割り当てると、2次元で影をつけた平坦なナビゲーションバーができ上がる図1⁠。擬似要素と変形を加えて立体的にしていく。

* {
    box-sizing: border-box;
}
html,
body {
    width: 100%;
    height: 100%;
}
body {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f2f2f2;
}
li {
    list-style: none;
}
.list-item {
    background: #000;
    color: #575757;
    text-align: center;
    height: 2.5em;
    width: 4em;
    line-height: 2.5em;
    border-bottom: 1px solid #060606;
    position: relative;
    display: block;
    box-shadow: -2em 1.5em 0 #e1e1e1;
}
図1 擬似要素と変形を加える前のナビゲーションバー
図1 擬似要素と変形を加える前のナビゲーションバー

ナビゲーションバーを3次元風に見せる

今回のお題のミソは、3次元の変形を使わないということだ。前掲サンプル1をよくよく眺めれば、パース(遠近法)がかかっていない。擬似要素::before::afterで、ナビゲーションバーの側面に見える部分を、つぎのCSSのとおりtransformプロパティで2次元に変形して加える図2⁠。傾斜は関数skewX()skewY()で、それぞれの軸方向に傾ける角度を渡す。

.list-item::before,
.list-item::after {
    content: "";
    position: absolute;
    width: 0.5em;
}
.list-item::after {
    height: 4em;
    background: #181818;
    bottom: -2.25em;
    left: 1.5em;
    transform: rotate(90deg) skewY45deg);
}
.list-item::before {
    height: 2.5em;
    background: #121212;
    top: .25em;
    left: -0.5em;
    transform: skewY(-45deg);
}
図2 擬似要素でナビゲーションバーの側面を加えた
図2 擬似要素でナビゲーションバーの側面を加えた

そのうえで、ナビゲーションバー全体の要素class属性"nav-bar")をつぎのように斜めに傾けて、立体的に見せる図3⁠。なお、関数skew()を用いると、xとyのふたつの引数が渡せる。だが、最近の仕様からは除かれた。ブラウザによっては実装が残っているものの、使わない方がよい。動きを加える前の、立体風に見えるナビゲーションバーのCSSの定めは、以下のコード1にまとめた。

.nav-bar {
    transform: rotate(-35deg) skewX(20deg) skewY(5deg);
}
図3 立体風になったナビゲーションバー
図3 立体風になったナビゲーションバー
コード1 立体風のナビゲーションバー
* {
    box-sizing: border-box;
}
html,
body {
    width: 100%;
    height: 100%;
}
body {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f2f2f2;
}
.nav-bar {
    transform: rotate(-35deg) skewX(20deg) skewY(5deg);
}
li {
    list-style: none;
}
.list-item {
    background: #000;
    color: #575757;
    text-align: center;
    height: 2.5em;
    width: 4em;
    line-height: 2.5em;
    border-bottom: 1px solid #060606;
    position: relative;
    display: block;
    box-shadow: -2em 1.5em 0 #e1e1e1;
}
.list-item::before,
.list-item::after {
    content: "";
    position: absolute;
    width: 0.5em;
}
.list-item::after {
    height: 4em;
    background: #181818;
    bottom: -2.25em;
    left: 1.5em;
    transform: rotate(90deg) skewY(45deg);
}
.list-item::before {
    height: 2.5em;
    background: #121212;
    top: .25em;
    left: -0.5em;
    transform: skewY(-45deg);
}

マウスポインタが重なったときのアニメーションを加える

それぞれのボタンの要素class属性"list-item")にマウスポインタを重ねたら:hover擬似クラス⁠⁠、つぎのように位置や大きさを変えることにより、飛び出したように見せる図4⁠。影もそれに合わせて動かした。

.list-item:hover {
    background: #ff6e42;
    color: #fffcfb;
    transform: translate(0.9em, -0.9em);
    box-shadow: -2em 2em 0 #e1e1e1;
}
.list-item:hover::before {
    background: #b65234;
    width: 1em;
    top: 0.5em;
    left: -1em;
}
.list-item:hover::after {
    background: #b65234;
    width: 1em;
    bottom: -2.5em;
    left: 1em;
    height: 4em;
}
図4 マウスポインタを重ねると飛び出して見える
図4 マウスポインタを重ねると飛び出して見える

あとは、つぎのようにtransitionプロパティで滑らかなアニメーションにすればよい。機械的な動きにするため、タイミング関数はlinearを用いた。書き上がったCSSの定めは、以下のコード2にまとめた。

.list-item {

    transition: 0.25s linear;
}

.list-item::before,
.list-item::after {

    transition: 0.25s linear;
}
コード2 マウスポインタを重ねるとボタンが飛び出す3D風のナビゲーションバー
* {
    box-sizing: border-box;
}
html,
body {
    width: 100%;
    height: 100%;
}
body {
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f2f2f2;
}
.nav-bar {
    transform: rotate(-35deg) skewX(20deg) skewY(5deg);
}
li {
    list-style: none;
}
.list-item {
    background: #000;
    color: #575757;
    text-align: center;
    height: 2.5em;
    width: 4em;
    line-height: 2.5em;
    border-bottom: 1px solid #060606;
    position: relative;
    display: block;
    box-shadow: -2em 1.5em 0 #e1e1e1;
    transition: 0.25s linear;
}
.list-item:hover {
    background: #ff6e42;
    color: #fffcfb;
    transform: translate(0.9em, -0.9em);
    box-shadow: -2em 2em 0 #e1e1e1;
}
.list-item:hover::before {
    background: #b65234;
    width: 1em;
    top: 0.5em;
    left: -1em;
}
.list-item:hover::after {
    background: #b65234;
    width: 1em;
    bottom: -2.5em;
    left: 1em;
    height: 4em;
}
.list-item::before,
.list-item::after {
    content: "";
    position: absolute;
    width: 0.5em;
    transition: 0.25s linear;
}
.list-item::after {
    height: 4em;
    background: #181818;
    bottom: -2.25em;
    left: 1.5em;
    transform: rotate(90deg) skewY(45deg);
}
.list-item::before {
    height: 2.5em;
    background: #121212;
    top: .25em;
    left: -0.5em;
    transform: skewY(-45deg);
}

おすすめ記事

記事・ニュース一覧