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

第19回画像のアコーディオン表示

今回は、アコーディオンのように開く画像をお題とするサンプル1⁠。Image Accordion with CSS3のコードにもとづいて、組み立てをわかりやすく改め、行数も絞り込んだ。どの画像を選び、その前にどれが開いていたかにより、動きが少しずつ違っておもしろい。

サンプル1 CSS3: Image Accordion

インタラクションを加える前のページレイアウト

インタラクションを加える前の静的な組み立てから確かめよう。まず<head>要素だ。WebフォントとしてGoogle Fontsから、つぎのようにOpen Sans Condensedを用いる(bold 700を含めた⁠⁠。いつもどおり、-prefix-freeもCDNから読み込んだ(第16回の水平に並べた要素に静的なスタイルを割り当てる参照⁠⁠。

<head>要素
<link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300,700" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>

画像のひとつのパネルは、つぎのように<figure>要素class属性)にまとめた。中には、画像の<img>class属性"accordion-image")と選択のタブとなるラジオボタンの<input>class属性"accordion-tab")や画像の上に置くキャプションの<figcaption>class属性"accordion-caption")などの要素が含まれる。

<figure class="accordion-panel">
    <img class="accordion-image" src=画像ファイルのパス alt=代替テキスト />
    <input class="accordion-tab" type="radio" name="radio-set" checked="checked"/>
    <figcaption class="accordion-caption"><span>stroll</span></figcaption>

</figure>

今回のお題で少し変わっているのは、この画像のアコーディオンがつぎのようにパネル<figure>要素)の入れ子でつくられていることだ。親を動かせば、子も揃ってしたがう。これが、このアニメーションのひとつのポイントとなる。

<div class="container">
    <figure class="accordion-panel">
        <!-- パネル01 -->
        <figure class="accordion-panel">
            <!-- パネル02 -->
            <figure class="accordion-panel">
                <!-- パネル03 -->
                <figure class="accordion-panel">
                    <!-- パネル04 -->
                    <figure class="accordion-panel">
                        <!-- パネル05 -->
                    </figure>    
                </figure>
            </figure>
        </figure>
    </figure>
</div>

このHTMLのコードにつぎの<style>要素のとおりCSSを定めると、アコーディオンの画像パネルが揃う図1⁠。インタラクションを加える前なので、おもに位置合わせだ。幅は、表示画像(240px)とタブ(40px)から全体(400px = 240 + 40×4)を決めている。また、先頭のパネルは、位置を左端にした。このセレクタには結合子>を用いている。要素の直接の子を示す。このお題ではパネルを入れ子にしたこともあって、ふたつのセレクタの関係から要素を定める結合子をいくつか使うので、以下の表1にまとめた(MDN関係ベースのセレクタ参照⁠⁠。ここまでの要素<body><style>の定めは、以下のコード1のとおりだ。

<style>要素
.container {  /* アコーディオン全体 */

    width: 400px;  /* 全体の幅 */

    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.08);
    border: 7px solid rgba(255, 255, 255, 0.6);
}
.accordion-panel {  /* パネル */

    position: absolute;

    left: 40px;  /* タブとして見せる幅 */
    width: 240px;  /* 画像の幅 */
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6);
}
.container > .accordion-panel {  /* 先頭のパネル */
    position: relative;
    left: 0;
}

.accordion-tab {  /* タブ */

    width: 40px;  /* 反応する幅 */
    height: 100%;
    cursor: pointer;
    z-index: 100;
}
.accordion-caption span {  /* キャプション */

    text-transform: uppercase;

    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
}
図1 インタラクションを加える前の画像パネルのレイアウト
図1 インタラクションを加える前の画像パネルのレイアウト
表1 ふたつのセレクタの関係から要素を定める結合子
結合子構文選択要素
子セレクタ>A > BセレクタAの要素の直接の子で、セレクタBに合う要素
一般兄弟セレクタ~A ~ Bふたつのセレクタに共通の親要素があるとき、セレクタAの要素より後ろにあって、セレクタBに合う要素
隣接セレクタ+A + BセレクタAの要素の後にあって、セレクタBに合うはじめの要素

コード1 インタラクションを加える前のもととなるHTMLコードとスタイル
<body>要素

<div class="container">
    <figure class="accordion-panel">
        <img class="accordion-image" src="images/photo_01.png" alt="image01" />
        <input class="accordion-tab" type="radio" name="radio-set" checked="checked"/>
        <figcaption class="accordion-caption"><span>stroll</span></figcaption>
        <figure class="accordion-panel">
            <img class="accordion-image" src="images/photo_02.png" alt="image02" />
            <input class="accordion-tab" type="radio" name="radio-set" />
            <figcaption class="accordion-caption"><span>families</span></figcaption>
            <figure class="accordion-panel">
                <img class="accordion-image" src="images/photo_03.png" alt="image03" />
                <input class="accordion-tab" type="radio" name="radio-set" />
                <figcaption class="accordion-caption"><span>fawn on</span></figcaption>
                <figure class="accordion-panel">
                    <img class="accordion-image" src="images/photo_04.png" alt="image04" />
                    <input class="accordion-tab" type="radio" name="radio-set" />
                    <figcaption class="accordion-caption"><span>solitary</span></figcaption>
                    <figure class="accordion-panel">
                        <img class="accordion-image" src="images/photo_05.png" alt="image05" />
                        <input class="accordion-tab accordion-tab-last" type="radio" name="radio-set" />
                        <figcaption class="accordion-caption"><span>conversation</span></figcaption>
                    </figure>    
                </figure>
            </figure>
        </figure>
    </figure>
</div>
<style>要素
body{
    font-family: 'Open Sans Condensed','Arial Narrow', serif;
    background-color: aliceblue;
}
.container {
    position: relative;
    width: 400px;
    margin: 20px auto;
    overflow: hidden;
    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.08);
    border: 7px solid rgba(255, 255, 255, 0.6);
}
.accordion-panel {
    margin: 0;
    position: absolute;
    top: 0;
    left: 40px;
    width: 240px;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6);
}
.container > .accordion-panel {
    position: relative;
    left: 0;
}
.accordion-image {
    display: block;
}
.accordion-tab {
    position: absolute;
    top: 0;
    width: 40px;
    height: 100%;
    cursor: pointer;
    z-index: 100;
}
.accordion-caption span {
    position: absolute;
    top: 40%;
    margin-top: -20px;
    left: 20px;
    right: 20px;
    text-align: center;
    background: rgba(47, 79, 79, 0.25);
    line-height: 10px;
    font-size: 18px;
    text-transform: uppercase;
    letter-spacing: 4px;
    font-weight: 700;
    padding: 20px;
    color: #fff;
    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
}

クリックしたタブの画像を開く

タブにするラジオボタンclass属性"accordion-tab")をクリックしたら:checked擬似クラス⁠、そのパネルclass属性"accordion-panel")が開くようにしたい。その場合のCSSの定めは、つぎのように簡単だ。すぐ右のパネルつまり直接の子要素を子セレクタ>で探して、画像幅分右にずらせばよい図2⁠。

.accordion-tab:checked ~ .accordion-panel {
    left: 240px;
}
図2 クリックしたタブの画像が開く
図2 クリックしたタブの画像が開く

画像の左端のタブclass属性"accordion-tab")の領域では、マウスポインタを指差しカーソルに変えているので、ラジオボタンは見えなくてよい。そこで、つぎのようにopacityプロパティを透明(0)にした。キャプションのテキストが書かれた<span>要素も、はじめは透明にしておく。細かいところでもうひとつ、開いたパネルのタブ:checked擬似クラス)では指差しカーソルに変える必要がない(前掲図2参照⁠⁠。そのため、位置を右端に追いやったうえで、幅はつぶした図3⁠。

.accordion-tab {

    opacity: 0;

}
.accordion-tab:checked {
    right: 0;
    width: 0;
}

.accordion-caption span {

    opacity: 0;

}
図3 ラジオボタンは消えてタブが正しく反応する
図3 ラジオボタンは消えてタブが正しく反応する

transitionプロパティをつぎのように定めれば、滑らかなアニメーションになる。選んだパネル:checked擬似クラス)の右つまり直下の子要素(子セレクタ>を右に開き、すでに開いていた他のパネルは戻す。アニメーションの時間に差を設けたので、開く親と戻る子のパネルの動きが組み合わさって、おもしろいアニメーションになる。ここまでのCSSの定めを、以下のコード2にまとめた。

.accordion-panel {

    transition: 0.3s ease-in-out;
}

.accordion-tab:checked ~ .accordion-panel {

    transition: 0.7s ease-in-out;
}
コード2 タブで選ばれた画像パネルがアコーディオンのように開く
body{
    font-family: 'Open Sans Condensed','Arial Narrow', serif;
    background-color: aliceblue;
}
.container {
    position: relative;
    width: 400px;
    margin: 20px auto;
    overflow: hidden;
    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.08);
    border: 7px solid rgba(255, 255, 255, 0.6);
}
.accordion-panel {
    margin: 0;
    position: absolute;
    top: 0;
    left: 40px;
    width: 240px;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6);
    transition: 0.3s ease-in-out;
}
.container > .accordion-panel {
    position: relative;
    left: 0;
}
.accordion-image {
    display: block;
}
.accordion-tab {
    position: absolute;
    top: 0;
    width: 40px;
    height: 100%;
    cursor: pointer;
    opacity: 0;
    z-index: 100;
}
.accordion-tab:checked {
    right: 0;
    width: 0;
}
.accordion-tab:checked ~ .accordion-panel {
    left: 240px;
    transition: 0.7s ease-in-out;
}
.accordion-caption span {
    position: absolute;
    top: 40%;
    margin-top: -20px;
    left: 20px;
    right: 20px;
    text-align: center;
    background: rgba(47, 79, 79, 0.25);
    line-height: 10px;
    font-size: 18px;
    opacity: 0;
    text-transform: uppercase;
    letter-spacing: 4px;
    font-weight: 700;
    padding: 20px;
    color: #fff;
    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
}

タブとキャプションのアニメーションを加える

タブを選ぶときのインタラクションにもうひと手間加えよう。つぎのように、キャプションの要素class属性"accordion-caption")をパネルの大きさに広げて、暗い半透明の背景色で重ねる。タブを選んだり:checked擬似クラス⁠⁠、マウスポインタを重ねた:hover擬似クラス)要素の背景色を透明に近づければ、開いた画像や選ぼうとするタブが明るくなる図4⁠。

.accordion-caption {
    width: 100%;
    height: 100%;
    background: rgba(47, 79, 79, 0.25);
    position: absolute;
    top: 0;
    transition: 0.2s linear;
}

.accordion-tab:checked + .accordion-caption {
    background: rgba(47, 79, 79, 0);
}

.accordion-tab:hover + .accordion-caption {
    background: rgba(47, 79, 79, 0.1);
}
図4 開いた画像とポインタを重ねたタブが明るくなる
図4 開いた画像とポインタを重ねたタブが明るくなる

仕上げにキャプションclass属性"accordion-caption")のテキストの<span>要素をアニメーションさせよう。透明から不透明にフェードインするとともに、少し上の位置から下がってくる。書き上がったCSSの記述は、以下のコード3にまとめたとおりだ。

.accordion-tab:checked + .accordion-caption span {
    opacity: 1;
    top: 50%;
    transition: 0.4s ease-in-out 0.5s;
}
コード3 タブでアコーディオンのように開閉する画像パネルとフェードインするキャプション
body{
    font-family: 'Open Sans Condensed','Arial Narrow', serif;
    background-color: aliceblue;
}
.container {
    position: relative;
    width: 400px;
    margin: 20px auto;
    overflow: hidden;
    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.08);
    border: 7px solid rgba(255, 255, 255, 0.6);
}
.accordion-panel {
    margin: 0;
    position: absolute;
    top: 0;
    left: 40px;
    width: 240px;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6);
    transition: 0.3s ease-in-out;
}
.container > .accordion-panel {
    position: relative;
    left: 0;
}
.accordion-image {
    display: block;
}
.accordion-tab {
    position: absolute;
    top: 0;
    width: 40px;
    height: 100%;
    cursor: pointer;
    opacity: 0;
    z-index: 100;
}
.accordion-tab:checked {
    right: 0;
    width: 0;
}
.accordion-tab:checked ~ .accordion-panel {
    left: 240px;
    transition: 0.7s ease-in-out;
}
.accordion-caption {
    width: 100%;
    height: 100%;
    background: rgba(47, 79, 79, 0.25);
    position: absolute;
    top: 0;
    transition: 0.2s linear;
}
.accordion-caption span {
    position: absolute;
    top: 40%;
    margin-top: -20px;
    left: 20px;
    right: 20px;
    text-align: center;
    background: rgba(47, 79, 79, 0.25);
    line-height: 10px;
    font-size: 18px;
    opacity: 0;
    text-transform: uppercase;
    letter-spacing: 4px;
    font-weight: 700;
    padding: 20px;
    color: #fff;
    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.1);
}
.accordion-tab:checked + .accordion-caption {
    background: rgba(47, 79, 79, 0);
}
.accordion-tab:checked + .accordion-caption span {
    opacity: 1;
    top: 50%;
    transition: 0.4s ease-in-out 0.5s;
}
.accordion-tab:hover + .accordion-caption {
    background: rgba(47, 79, 79, 0.1);
}

おすすめ記事

記事・ニュース一覧