今回は、アコーディオンのように開く画像をお題とする(サンプル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 ふたつのセレクタの関係から要素を定める結合子
結合子 構文 選択要素
子セレクタ>
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 クリックしたタブの画像が開く
画像の左端のタブ(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 ラジオボタンは消えてタブが正しく反応する
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 開いた画像とポインタを重ねたタブが明るくなる
仕上げにキャプション(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);
}