JavaScript を使わず、CSS のみで複数のモーダルウィンドウを開閉するアイテムの一覧のサンプルコードをつくってみました。
例えば、EC サイトで商品一覧のサムネイルをクリックすると、その商品の拡大画像と説明、価格、購入ボタンなどをまとめたモーダルウィンドウが最前面に固定表示されるようなイメージです。
アイテムをクリックすると、サムネイルが回転しながらモーダルウインドウ上の画像と同一サイズに拡大してめくれるようにモーダルウィンドウに差し替わるようなもを考えていましたが、HTMLの構造上、要素の階層と position
の関係で、どうしても CSS のみではイメージするアニメーションができなかったため、最終的にはサムネイルをフレームアウトさせてモーダルウインドウをフレームインさせるという、かなりやっつけで不完全な形でのデモですが、参考までにどうぞ。
デモ
See the Pen
Toggle modal windows for detail with pure CSS by digistate (@digistate)
on CodePen.
このサンプルコードの動作を簡単に解説します。
モーダルウィンドウの開閉の仕組み
過去記事でもいくつか紹介していますが、CSS だけでクリック動作を検知するには、input
要素のチェックボックスを利用します。
チェックボックスでは、:checked
という疑似セレクタによってチェックの有無に分けて隣接する要素も含めてスタイリングできるため、チェックがない場合(初期状態)はモーダルウィンドウの要素は非表示にしておき、チェックされたとき(:checked
でのスタイル)にはモーダルウィンドウを表示するようにします。
参考 : 過去記事
また、:checked
以外にも、:target
疑似セレクタを利用して何らかの要素の表示有無の制御も可能です。
HTML の基本構造
個々のサムネイルの要素は、チェックボックスが含まれる以下のような構成にします。
<div class="panel-item"> <!-- 表示有無を判別するためのチェックボックス(非表示) --> <input type="checkbox" class="panel-check" id="panel1" aria-hidden="true" /> <!-- サムネイル --> <label for="panel1" class="panel-label" role="button"> <span class="label-inner"> <span class="thumbnail" style="background-image:url(サムネイルURL);"></span> </span> </label> <!-- モーダルウィンドウ(非表示) --> <div class="panel-modal"> <figure> <img src="画像URL" alt="image" /> </figure> </div> </div>
一覧に表示する数(サムネイル)は、このパネルアイテム(.panel-item
)が1つの単位となり、子要素にはチェックボックスの状態を変更可能にするための label
要素(サムネイル)と、このパネルに対応するモーダルウィンドウ用の要素(.panel-modal
)が構成されています。
label
要素の子要素には div
を含めることができないため、span
タグで強引に次ぐ強引なタグ構成でサムネイルを background-image
プロパティで表示しています。
なお、img
タグも label
内に含めることができるようです。
参考
https://stackoverflow.com/questions/18609554/is-div-inside-label-block-correct
CSSの構造
サムネイル(label)のスタイリング
チェックボックスのトリガーとなるサムネイルのラッパー要素(label
)の ::before
疑似セレクタには、サムネイルと同じサイズのレイヤーを一番下に重ね合わせておきます。
こうすることで、モーダルウィンドウが表示される際にアニメーションしてフレームアウトしても、ラッパー要素のサイズは保持されるため、サムネイルの一覧のレイアウトが崩れません。
サイズ保持用のレイヤー
.panel-label::before{ position:relative; content:''; display:inline-block; width:14vw; height:20vw; min-width:180px; min-height:260px; }
さらに、ラッパー要素の ::after
疑似セレクタは、フルスクリーンサイズの不透明なブラックレイヤーにし、初期状態では非表示にしてモーダルウィンドウが表示(チェックボックスにチェック)された際にその下に表示されるようにします。
ラッパー要素(label
)はチェックボックスのトリガーとなるため、この ::after
疑似セレクタのレイヤーがクリックされる(チェックボックスが外れる)と、モーダルウィンドウはフレームアウトしてサムネイルが元の位置に戻ってきます。
モーダルウィンドウを閉じるためのレイヤー
.panel-label::after{ content:''; position:fixed; top:0; left:0; right:0; bottom:0; z-index:1; background-color:rgba(#000, 0.78); pointer-events:none; opacity:0; transition:all .8s ease; cursor:zoom-out; }
モーダルウィンドウのスタイリング
モーダルウィンドウは、position:fixed
にして位置を固定し、表示されるときには常にスクリーンの中央に表示されるようにします(初期状態ではフレームアウトしています)。
また、先述のモーダルウィンドウを閉じるレイヤーよりも前面に表示させるため、z-index
の値は .panel-label::after
よりも大きい値にします。
.panel-modal{ position:fixed; top:50%; left:50%; width:90vw; height:90vh; min-width:320px; max-width:980px; max-height:860px; transform:translate(-50%, 100vh) rotateY(180deg); background-color:rgba(255,255,255,.1); overflow:auto; visibility:hidden; opacity:0; transition:all .8s ease; z-index:2; }
モーダルウィンドウを表示するときのスタイリング
表示するときのスタイリングは、チェックボックスの :checked
疑似セレクタを利用し、さらにチェックボックスの次にあるサムネイルのラッパー要素(.panel-label
)については「隣接兄弟結合子(+
)」を利用します。
サムネイルのスタイリング
.panel-check:checked + .panel-label .label-inner{ /* サムネイルをフレームアウトさせるCSS */ transform:perspective(1800px) rotateY(180deg) translate(50%, calc(100vh + 100%)); transition-delay:0s; width:90vw; height:90vh; min-width:320px; animation: changePosition 0s; animation-delay: .8s; animation-fill-mode: forwards; opacity:0; }
サムネイルは、animation
プロパティを指定していますが、これは position
は transform
の対象にすることはできないため、animation
プロパティで @keyframes
によって指定時間後に position
の値を fixed に変更するという、かなりの力技をやっています。
チェックボックスから2つ目にあるモーダルウィンドウ(.panel-modal
)には「一般兄弟結合子(~
)」を指定することで表現できます。
モーダルウィンドウのスタイリング
.panel-check:checked ~ .panel-modal{ /* モーダルウィンドウをフレームインするCSS */ visibility:visible; opacity:1; transition-delay:.66s; transform:translate(-50%, -45vh) rotateY(0); /* 中央に移動 */ }
サンプルで適当に作ってみましたが、やはり CSS のみでは色々と限界がありました。。
その他参考
https://stackoverflow.com/questions/35624241/delay-css-position-change-with-pure-css