CSS / animation

grid-template-rows を使用して、コンテンツの高さを制御するアコーディオン

─ Guide to page sections ─

scroll-driven animations に目が慣れてくると、アコーディオンなどは開くだけでは物足りなくて、アニメーションがスルスルと動いてくれないと満足さを感じない。そこで html と CSS で作るアコーディオンとその関連を追及してみよう。

アコーディオンをマスター
アコーディオンのコンテンツに何でも入れたい

First

画像とキャプション

段落の中で使い回すものに画像がある。画像にはキャプションが付属するが、キャプションの表示方式をアコーディオン風に開いて表示させるとどうなるか、やってみよう。

<figure> は HTML の要素で、図表などの自己完結型のコンテンツを表し、任意で <figcaption> 要素を使用して表されるキャプションを付けることができる。

A bout de souffle, Release: March 16 1960
actress: Jean Seberg

キャプションの文字の量を自由にしておくと、画像の下にだらしなくブラ下がるだけでしまりがないと感じることがある。であるなら画像の内側へ移動させてみる。リンクにしてもキャプションの文字から張れば分かり易いと思う。そんな訳でこういうのを模索してみた。

syd barrett

Syd Barrett

January 6, 1946 - July 7, 2006

活動:1967年に ピンクフロイド がメジャー・デビューすると、その端正な容姿と斬新な音楽性でバンドを成功へと導いた。

syd barrett

Syd Barrett

January 6, 1946 - July 7, 2006

<figure class="figurefx pushup">
  <img src="images/syd_barrett-3.jpg" alt="syd barrett">
  <figcaption>
    <h2>Syd Barrett</h2>
    <p>January 6, 1946 - July 7, 2006</p>
  </figcaption>
</figure>

適切にリンクにスタイルを適用するには、LVHA 順: :link :visited :hover :active で定義されるようにする。

:hover 時のアニメーションは 以下のように画像と figcaption に対して CSS を設定する。

figure.pushup:hover img {
  	-moz-transform: translate3d(0, -20px, 0); /* 視差効果を出すために画像を垂直方向に少し移動する */
  	-webkit-transform: translate3d(0, -20px, 0);
  	transform: translate3d(0, -20px, 0);
    opacity: 1;
}
figure.pushup:hover figcaption{
  	-moz-transform: translate3d(0, -100%, 0); /* キャプションを完全に表示するには、キャプションを垂直に上に移動する */
  	-webkit-transform: translate3d(0, -100%, 0);
  	transform: translate3d(0, -100%, 0);
  	-moz-transition: all 0.5s;
  	-webkit-transition: all 0.5s;
  	transition: all 0.5s;
    box-shadow: 0px -2px 28px rgba(0, 0, 0, 0.3);
}

Second

<details>: 詳細折りたたみ要素

<details> は HTML の要素で、ウィジェットが「開いた」状態になった時のみ情報が表示される折りたたみウィジェットを作成する。概要やラベルは <summary> 要素を使用して提供する必要がある。

以下「Details」をタップすると基本構造が理解できる。

Details

<details> は HTML の要素で、ウィジェットが「開いた」状態になった時のみ情報が表示される折りたたみウィジェットを作成する。概要やラベルは <summary> 要素を使用して提供する必要がある。

<details>
  <summary>Details</summary>
  Something small enough to escape casual notice.
</details>
details {
  border: 1px solid #aaa;
  border-radius: 4px;
  padding: 0.5em 0.5em 0;
}

summary {
  font-weight: bold;
  margin: -0.5em -0.5em 0;
  padding: 0.5em;
}

details[open] { /* ウィジェットを表示状態のとき */
  padding: 0.5em;
}

details[open] summary {
  border-bottom: 1px solid #aaa;
  margin-bottom: 0.5em;
}

参考: mdn web docs <details>: 詳細折りたたみ要素

さて、HTML の要素の「details タグと summary タグの組み合わせ」をどこまで手を加えていけるか、試してみたのが以下のサンプルである。

<summary> 要素は list-style 一括指定プロパティや、 list-style-type などの個別指定プロパティに対応しており、折りたたみウィジェットを三角形から選択したものに変更することができる (ふつうは list-style-image) を使用する。例えば、折りたたみウィジェットのアイコンは list-style: none と設定することで削除することができる。

「transition」を使ってアニメーションを実装してみる。少しは動きが良くなっただろうか。この辺りが限界だろう。

details { 
  transition: background 0.3s; transition: all 0.3s; 
}
details[open] { 
  transition: all 0.6s; 
}
html と CSS で作るアコーディオン
transition を使用して動きを加えたサンプル

Third

.max-height が解決するその役割

max-height は CSS のプロパティで、要素の最大高を設定する。これは height プロパティの使用値が、 max-height に指定した値を上回ることを防ぐ。また、max-height は height を上書きするが、 min-height は max-height を上書きする。

max-height を指定する値は、auto、px、% で記述することができる。

max-height を指定した高さを使ったアニメーションするサンプルが次の図である。タップするとサンプルページへ飛ぶ。

max-height の使いどころ
height: auto; はアニメーション効果が無効になる。(jQuery 使用)

Fourth

html と CSS だけでアニメーションのアコーディオンを作る

垂直に折りたたむアコーディオンを html と CSS だけで作る、これが上手くいけば万々歳なのだがどうだろう。

かなりの種類のアコーディオンを試してみて、以下が必要条件として挙げられる。

  • ひとつひとつの開くアコーディオンの高さが内包されるコンテンツに応じた高さになること。
  • コンテンツの中で段落に使われる全てのタグが入ること。
  • アコーディオンが開くときのアニメーションは気持ちよくスルスルと動作すること。多分これが一番の最難関だろう。
html と CSS で作るアコーディオン
アコーディオンのコンテンツに何でも入れたい

参考: Transitioning to Height Auto (Two Ways)


Fifth

jQuery で実現できるアニメーション

直前のセクションが本来ならば、このページの帰結であった。何度も繰り返して動作確認をしているうちに html と CSS で作るアニメーションの動き方に、どうも気持ちよく馴染めない思いが残る。

やはり JavaScript もしくは jQuery の力を借りてアニメーションしなければならないのだろうか。そこで過去にアーカイブしたものや最近のものも含めて以下をピックアップしてみた。

html と CSS で作るアコーディオン
アコーディオンのコンテンツに何でも入れたい
html と CSS で作るアコーディオン
スルスルッと動きが良い
アコーディオン
アコーディオンが連続するページ

様々な環境下で試してみる。例えば、上記のように、別ページにアコーディオンだけを単独で書き出してみる。アコーディオンで一杯のサンプルも同様であるが、段落の中に差し込まれるそれと、動きが違ってスムーズに感じるということは、アオコーディオンが配置される前後のレイアウトが影響していると思われる。


Sixth

grid-template-rows でコンテンツの高さを制御する方法

That's marvelous! このページ最後に紹介するのが、grid-template-rows を使用した特別なアコーディオンである。以下の赤いボタンに集約されている。こういう具合に、ページの段落にアコーディオンを挿入して、赤いボタンをタップするとコンテンツがスルスルッと開く。

pinkfloyd

Pinkfloyd…活動期間 1965年 - 2014年。

現代社会における人間疎外や政治問題をテーマにした文学的・哲学的な歌詞で、世界的に有名なバンドとなる。プログレッシブ・ロックとして評価を得る。

Syd barrett

Syd Barrett…January 6, 1946 - July 7, 2006

1967年にピンクフロイドがメジャー・デビューすると、その斬新な音楽性でバンドの方向性を導いたコアメンバー(ヴォーカリスト兼ギタリスト)である。

親ラッパー(grid-template-rows)で展開されたクラスを切り替えるだけで、アニメーションが機能する。以下はラッパー構造を示した図である。

grid-template-rows を使用して、コンテンツの高さを制御するアコーディオン
(参考)grid-template-rows の概略
<!-- accordion -->
<div class="accord">
  <button id="toggle">Accordion Content
  </button>
  <!-- content -->
  <div id="content">
    <!-- inside -->
    <div class="inside">
      <!-- ad-content -->
      <div class="ad-content">
        <img src="images/orange.gif" width="100%" height="50%" alt="dammy">
      </div>
      <!-- //ad-content -->
    </div>
    <!-- //inside -->
  </div>
  <!-- //content -->
</div>
<!-- //accordion -->
  • <div class="accord">アコーディオンの横幅サイズを設定する。
  • button id="toggle">アコーディオンを開閉するボタンを設定する。JavaScript を設定して、onclick で on では「.expanded」を「#content」に付け、off では「.expanded」を外す。
  • <div id="content">display: grid; rid-template-rows: 0fr; を設定して、初期状態を非表示にする。
    続いて、transition: 1s; と overflow: hidden; /* 開閉する部分が表示された際にはみ出した分が表示されないようにする */ を併記する。
  • <div class="inside">min-height: 0; を設定する。min-height の値が max-height および height の値より大きい場合は、min-height の値が要素の高さになる。
  • <div class="ad-content"> ここにアコーディオンのコンテンツである<img>や<h1>や<p>が入る。
  • CSS のみに以下を設定する
    #content.expanded {grid-template-rows: 1fr; }
    高さが付くと、開閉する。
.accord {
    inline-size: 24rem;
    margin-inline: auto; /* 中央寄せ */
    font-family: "Noto Sans JP", sans-serif;
}

#content {
    display: grid;
    grid-template-rows: 0fr; /* 初期状態は、コンテンツを非表示 */
    transition: 1s;
    overflow: hidden; /* 開閉する部分が表示された際にはみ出した分が表示されないようにする */
}
#content .inside {
    min-height: 0;
}
#content .inside .ad-content {
    margin: 1em;
    border: #336633 3px solid;
    border-radius: 10px;
    padding: 1em;
    background: rgba(247, 247, 247,0.5);
}
#content.expanded {
    grid-template-rows: 1fr; /* 高さがつき、開閉する */
}

別ページで開くサンプル

JavaScript の構文

要素をクリックしたらという条件付けは、JavaScript を使って簡単に行なうことができる。JavaScript の onclick は、要素がクリックされたときに特定のアクションを実行するためのイベントハンドラーである。

<script>
toggle.onclick = () => {
	content.classList.toggle("expanded"); 
	// #content 要素に expanded をつけ外しする
};

</script>

参考: Transitioning to Height Auto (Two Ways)