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

第12回垂直に回転して切り替わる直方体のタブ

今回のお題は、タブにより表示要素を切り替える。ただし、例によってこけおどしの3次元の回転を採り入れようサンプル1⁠。コンテンツの画像と背景は、3面の直方体で組み立てた。タブをクリックすると、対応するコンテンツが垂直に回って正面に向く。3D Cube for tabbed contentの3次元表現とCSSを参考に、コードは絞り込み、わかりやすく組み立て直した。

サンプル1 CSS3: 3D Cube for tabbed content

スタイルを与える前の素のHTMLコード

まず、HTMLドキュメントの<body>要素には、つぎのようなHTMLのコードを加えた。CSSを与える前のHTMLドキュメントの表示と照らし合わせてもらうとよい図1⁠。タブのクリックで表示するコンテンツの<div>要素class属性"tab-content")は、ラジオボタンの<input>要素type属性"radio")で切り替える。もっとも、CSSでラジオボタンそのものは表示しない。<label>要素にfor属性でラジオボタンのid属性を与えれば、ラベルもラジオボタンと同じクリックの対象になる。

<div class="container">
    <label class="tab" for="tab-top">Child</label>
    <label class="tab" for="tab-front">Adult</label>
    <label class="tab" for="tab-bottom">Family</label>
    <input type="radio" name="tabs" id="tab-top">
    <input type="radio" name="tabs" id="tab-front">
    <input type="radio" name="tabs" id="tab-bottom"> 
    <div class="cube">
        <div class="tab-content">
            <div class="tab-image"><img src="images/pen01.png" alt=""></div>
            <h1>Child</h1>
        </div>
        <div class="tab-content">
            <div class="tab-image"><img src="images/pen02.png" alt=""></div>
            <h1>Adult</h1>
        </div>
        <div class="tab-content">
            <div class="tab-image"><img src="images/pen03.png" alt=""></div>
            <h1>Family</h1>
        </div>
    </div>
</div>
図1 CSSを与える前のHTMLドキュメントの表示
図1 CSSを与える前のHTMLドキュメントの表示

タブとコンテンツのテキストのフォントには、Google FontsのRobotoを用いた。また例によって、ベンダープレフィックスを省くため、<script>要素で-prefix-freeを読み込んである(第1回のベンダープレフィックスと-prefix-freeの項参照⁠⁠。

<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,500" rel="stylesheet">
<style>
/* ここにCSSを定める */
</style>
<script src="lib/prefixfree.min.js"></script>

コンテンツの直方体を静的に組み立てる

前掲のHTMLコードには、つぎのコード1のスタイルを与える。アニメーションや3次元表現はまだ加えていない。文字と画像や背景、それらの色と大きさ、および配置を定めた。とくに3次元表現を加えると、試行錯誤で細かな位置調整をしなければならない。perspectiveプロパティ(第4回の要素にポインタを重ねたら水平軸で回す参照)は、ここで定めておかないと位置決めがしにくいため先に適切な値を与えている。

コード1 <style>要素に定めたコンテンツの静的なスタイル
.container {
    perspective: 1200px;
    width: 400px;
    margin: 0 auto;
    font-family: 'Roboto', sans-serif;
    font-weight: 100;
    color: white;
    text-align: center;
}
input {
    display: none;
}
.tab {
    position: absolute;
    width: 80px;
    height: 70px;
    left: 325px;
    line-height: 70px;
    font-weight: 300;
}
.tab:nth-child(1) {
    background: mediumturquoise;
}
.tab:nth-child(2) {
    top: 74px;
    background: steelblue;
}
.tab:nth-child(3) {
    top: 148px;
    background: deeppink;
}
.cube {
    margin: 60px 10px auto;
    width: 300px;
}
.tab-content {
    width: 300px;
    height: 200px;
    position: absolute;
}
.tab-content h1 {
    font-size: 30px;
    margin: 75px 115px;
    text-align: center;
    font-weight: 500;
}
.tab-content:nth-child(1) {
    background: mediumturquoise;
}
.tab-content:nth-child(2) {
    background: steelblue;
}

.tab-content:nth-child(3) {
    background: deeppink;
}
.tab-image {
    margin: 20px 30px;
    position: absolute;
}

タブとコンテンツの位置は、アニメーションと3次元表現をおいてひとまず決まった。ただ、コンテンツとその中の画像が少し小さい図2⁠。これは3次元でコンテンツを直方体に組み立てるとき、正面を少し手前にもってくるので、その分余裕をとっているからだ。あとのふたつのコンテンツは、まだその裏に重なっている。

図2 タブとコンテンツの静的なスタイル
図2 タブとコンテンツの静的なスタイル

3つのコンテンツを直方体に組み上げてタブで垂直に回す

それでは、まだアニメーションはさせないまま、3次元でコンテンツの3つの<div>要素class属性"tab-content")を直方体に組み上げよう。以下のようにtransformプロパティの3次元変換で、上面は上に90度回して持ち上げる。底面は下に90度回して下ろす。そのため、transform-originプロパティで変形の原点は、それぞれ上端中央と下端中央に定めた。正面は奥行きを手前に定めたので、少し大きさが増した図3⁠。この段階での見え方は、OSやブラウザなどの環境によって少し違うかもしれない。なお、タイトルの<h1>要素と画像の<div>要素class属性"tab-image")z-indexプロパティを与えたのは、画像の前にタイトルを出すためだ。

.tab-content h1 {

    z-index: 1;
}

.tab-content:nth-child(1) {
    transform: rotateX(90deg) translateY(-100px);
    transform-origin: top center;

}
.tab-content:nth-child(2) {
    transform: translateZ(100px);

}
.tab-content:nth-child(3) {
    transform: rotateX(-90deg) translateY(100px);
    transform-origin: bottom center;

}

.tab-image {

    z-index: -1;
}
図3 コンテンツを3次元の直方体に組み上げた
図3 コンテンツを3次元の直方体に組み上げた

これでコンテンツの3つの<div>要素class属性"tab-content")は直方体に組み上がった。といっても、回してみなければ確かめられない。タブのクリックに対するインタラクションには、つぎのように~結合子を用いる。前述のとおり、タブの<label>要素にfor属性でラジオボタン<input>要素)id属性を与えたことにより、タブのクリックでラジオボタンが選ばれる。そのラジオボタンに応じて、直方体の<div>要素class属性"")をx軸でそれぞれ異なる角度垂直に回した。あとは、直方体の<div>要素にtransitionプロパティを加えればアニメーションになる。なお、transform-originプロパティで変形の原点を決め、transform-styleで3次元の変形を定めている。でき上がったCSSの記述は、以下のコード2にまとめた。

.cube {

    transform-origin: center 100px;
    transform-style: preserve-3d;
    transition: transform 0.5s ease-in;
}

#tab-top:checked ~ .cube {
    transform: rotateX(-90deg);
}
#tab-front:checked ~ .cube {
    transform: rotateX(0deg);
}
#tab-bottom:checked ~ .cube {
    transform: rotateX(90deg);
}
コード2 タブのクリックで直方体のコンテンツを回す
.container {
    perspective: 1200px;
    width: 400px;
    margin: 0 auto;
    font-family: 'Roboto', sans-serif;
    font-weight: 100;
    color: white;
    text-align: center;
}
input {
    display: none;
}
.tab {
    position: absolute;
    width: 80px;
    height: 70px;
    left: 325px;
    line-height: 70px;
    font-weight: 300;
}
.tab:nth-child(1) {
    background: mediumturquoise;
}
.tab:nth-child(2) {
    top: 74px;
    background: steelblue;
}
.tab:nth-child(3) {
    top: 148px;
    background: deeppink;
}
.cube {
    margin: 60px 10px auto;
    width: 300px;
    transform-origin: center 100px;
    transform-style: preserve-3d;
    transition: transform 0.5s ease-in;
}
.tab-content {
    width: 300px;
    height: 200px;
    position: absolute;
}
.tab-content h1 {
    font-size: 30px;
    margin: 75px 115px;
    text-align: center;
    font-weight: 500;
    z-index: 1;
}
.tab-content:nth-child(1) {
    transform: rotateX(90deg) translateY(-100px);
    transform-origin: top center;
    background: mediumturquoise;
}
.tab-content:nth-child(2) {
    transform: translateZ(100px);
    background: steelblue;
}
.tab-content:nth-child(3) {
    transform: rotateX(-90deg) translateY(100px);
    transform-origin: bottom center;
    background: deeppink;
}
#tab-top:checked ~ .cube {
    transform: rotateX(-90deg);
}
#tab-front:checked ~ .cube {
    transform: rotateX(0deg);
}
#tab-bottom:checked ~ .cube {
    transform: rotateX(90deg);
}
.tab-image {
    margin: 20px 30px;
    position: absolute;
    z-index: -1;
}

おすすめ記事

記事・ニュース一覧