この記事はElectron Advent Calendar 2015 - Qiita2015の8日目の記事です。
今回の記事のサンプルコードは↓コチラ。
https://github.com/sourcechord/electron-gridlayout-sample
目次
前置き
CSSでのレイアウトって難しいですよね。。。
自分は今まで主に.net系のデスクトップアプリ開発をやってきましたが、ここ最近Web系の開発に手を出してみて、色々と勝手の違うCSSでのレイアウトにずいぶんと苦労しました。
XAML系のプログラミングだったらGridパネル、Androidの開発でのGridLayoutというような、いい感じにグリッドレイアウトを実現するためのものが現在のCSSにはありません。
なんで、よくあるこういうHoly Graylレイアウトを作るのにこんな苦労しなきゃいかんのか・・・と、ずいぶん頭を抱えてきました。
CSS Grid Layout Module Level 1
ですが、CSSでもグリッドレイアウトを定義するための仕様の策定が進んでいます。
CSS Grid Layout Module Level 1
「CSS Grid Layout Module Level 1」では、平面上をグリッドに分割して、任意の位置に要素を配置をしていくことができます。
この手のレイアウトはデスクトップアプリのようなUIのレイアウトととても相性がいいです。
また、MediaQueryと組み合わせてレスポンシブにUIのレイアウトを切り替えるのも行いやすく、まさにElectronでアプリ作る時にはバッチリ相性のよいレイアウト方法だと思います。
CSS Grid Layoutの各ブラウザの対応状況
この「CSS Grid Layout Module Level1」ですが、2015年12月現在の対応状況は以下のような状態です。
Can I use... Support tables for HTML5, CSS3, etc
Webサイトの作成などでは、当然使えるわけない!!って状況ですね。
対応状況について補足
- IE10以降やEdgeは部分的な対応となっていますが、以下のような状況です
- -ms-のベンダープレフィックスが必要
- ↓の古い仕様への対応(現在策定中の仕様とは少し異なるもの)
Grid Layout
- ChromeやFirefoxでは、拡張フラグを指定することで、実験的な機能として利用できます。
Chromiumを内部で使用するElectronのアプリでも、同様のフラグをONにすることでこの機能が使えるようになります。
メリット・デメリット?
現時点で標準になっていない機能(まだWorkingDraftの段階)なので、もちろんデメリットやリスクもあったりすると思います。
今後仕様が変わったりしても追従していく覚悟も必要ですし、まだ実装されていない部分や、不具合に遭遇する可能性も多々あると思います。
それに、学習するための情報もまだまだ少なめです。
ですが、レイアウトがこれだけシンプルで自由自在にできるようになるので、デメリットやリスクを補って余りある十分なメリットがあるのでは、という気がしています。
CSS Grid Layoutを使ってみる
参考サイト
CSS3 Grid Layoutの使い方については、下記ページでサンプルを交えて非常に詳しく説明してくれてます。
Grid by Example
今回はこれを参考に色々やってみます。
言葉の定義
まずは、Gridレイアウトで出てくる言葉の定義についてザックリと解説します。
Gridの中の、行や列/セルを表す単位は以下のようになっています。
Grid Line
この図で赤い線を引いている部分は、column 2のLineとなります。Grid Track
Grid中の1列or1行をまとめて指す単位がTrackです。Grid Cell
Grid中の特定の1コマを指定する単位がCellです。Grid Area
このように、複数のセルを矩形にまとめたGrid中の特定の領域を示す単位です。
Chromiumの拡張フラグを設定する
Electronでは、以下のappendSwitch
というメソッドでChromiumで使用する拡張フラグの設定ができます。
http://electron.atom.io/docs/v0.35.0/api/app/#app-commandline-appendswitch-switch-value
このメソッドを使って「試験運用版のウェブプラットフォームの機能」のオプションを有効にします。
以下のメソッドをMainプロセスのスクリプトに追記します。
App.commandLine.appendSwitch("--enable-experimental-web-platform-features");
これで準備OK。
単純なグリッドレイアウト
実際にGridを使ってレイアウトをやってみます。
まずは単純な配置から。
こんな感じのhtmlを用意します。
グリッドレイアウトを行うためのwrapperのdivを作り、その中にシンプルにdivを並べただけのものです。
<divclass="wrapper"><divclass="box">A</div><divclass="box">B</div><divclass="box">C</div><divclass="box">D</div><divclass="box">E</div></div>
gridレイアウトをする領域の定義
Gridレイアウトを行う領域に対して、display: grid
というプロパティを指定します。
- gridの分割数を定義
gridの分割数は、grid-template-columns/grid-template-rowsという二つのプロパティで、Gridの分割数やサイズを指定します。
ここでは、100px、150px、100pxという順番で3つの列と、高さが自動で計算される行を2つ定義します。
wrapperクラスの定義はこんな風になります。
.wrapper{display: grid; grid-template-columns: 100px150px100px; grid-template-rows: autoauto; }
設定する単位について
グリッドのサイズは、pxやem、remなどの指定方法の他に、以下のような方法が用意されています。
* auto
auto指定をすると、auto指定をした行/列のサイズは、実際にその行/列に配置された要素のサイズに合わせて決定されます。
* fr
グリッドのサイズを、配置可能な余白のサイズから比率で指定します。
(↓のように○○frなどといった感じで指定します。)
grid-template-columns: 1fr 2fr;
こうすると、幅が1:2になるように、二つの列を定義できます。
グリッド上に自動で流し込む場合
先ほど定義した2行3列のグリッドの領域内に複数の要素を入れてみます。
.wrapper{display: grid; grid-template-columns: 100px150px100px; grid-template-rows: autoauto; }.box{background-color: #444; color: #fff; border-radius: 5px; border: 2pxsolidblack; padding: 20px; font-size: 150%; }
<divclass="wrapper"><divclass="box">A</div><divclass="box">B</div><divclass="box">C</div><divclass="box">D</div><divclass="box">E</div></div>
こんな風に定義したグリッドに順番にdiv要素が流し込まれていきます。
流し込む方向の指定
grid-auto-flow
というプロパティを使うことで、自動で要素をグリッドに流し込む際に、行/列どちらの方向に順に流し込むかを指定できます。
.wrapper{display: grid; grid-template-columns: 100px150px100px; grid-template-rows: autoauto; grid-auto-flow: column; /*列方向に順に並べていくよう指定*/}
https://github.com/sourcechord/electron-gridlayout-sample/blob/master/view/flow_direction.html
グリッド上の特定の位置へ配置
今度は、htmlに定義した順に流し込むのではなく、cssでグリッド上の特定の位置を指定して配置してみます。 グリッド上の配置位置を指定するには、以下の4つのプロパティで、row/culumnの開始位置と終了位置を指定します。 * grid-row-start * grid-row-end * grid-column-start * grid-column-end
特定のセルに配置
.a{ grid-row-start: 1; grid-row-end: 2; grid-column-start: 2; grid-column-end: 3; }
複数のセルにまたがった配置
こんな風に、複数のセルにまたがって配置することもできます。
.b{ grid-row-start: 2; grid-row-end: 3; grid-column-start: 2; grid-column-end: 4; }
ショートハンド
gridの定義方法、配置方法ともに、簡潔に記述するためのショートハンドが用意されています。
グリッド定義のショートハンド
配置位置指定のショートハンド
Z-Indexの指定
z-index
プロパティを指定することで、要素のが重なった際の順序指定ができます。
htmlに定義した順ではなく、このz-index
プロパティの値の大きい方を前面に表示することができます。
https://github.com/sourcechord/electron-gridlayout-sample/blob/master/view/z_index.html
複雑なレイアウト
今度はもう少し複雑な例として、よくあるHolyGrail的なレイアウトを作ってみます。
htmlは↓みたいに、シンプルなものを用意しておきます。
<divclass="wrapper"><divclass="box header">header</div><divclass="box left">left</div><divclass="box content">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati debitis nemo excepturi voluptatibus magnam fugit officia, ut, dicta, animi inventore quidem aliquam adipisci vitae perspiciatis id autem maiores asperiores dolores!</div><divclass="box right">right</div><divclass="box footer">footer</div></div>
続いて、cssを書いていきます。
全体を、3×3のグリッドに分割します。
.wrapper{display: grid; width: 100%; height: 100%; grid-template-columns: 150px3fr 1fr; grid-template-rows: auto1fr auto; padding: 10px; }
配置は、こんな感じ。
ヘッダーやフッター領域は複数のセルからなるエリアを指定して、こんな形にしています。
.header{/*↓grid-areaで書く場合はこんな感じ*//*grid-area: 1/1/2/4;*/ grid-row: 1; grid-column: 1 / span 3; }.left{/*grid-area: 2/1/3/2;*/ grid-row: 2; grid-column: 1; }.content{overflow: auto; /*grid-area: 2/2/3/3;*/ grid-row: 2; grid-column: 2; }.right{/*grid-area: 2/3/3/4;*/ grid-row: 2; grid-column: 3; }.footer{/*grid-area: 3/1/4/4;*/ grid-row: 3; grid-column: 1 / span 3; }
わかりやすいですね。
grid-template-areasを使って、AA風にレイアウトを定義
grid-template-areas
プロパティを使うと、アスキーアートっぽく文字列でレイアウトの定義を行いつつ、エリアに名前を付けることができます。
先ほどのHolyGrail的なレイアウトの例を、grid-template-areasプロパティを使って書き直してみます。grid-template-areas
というプロパティを使い、グリッドの各セル/エリアに名前を付けていきます。
スペースで区切られた各文字列が一つのセルとなり、隣り合う同名のセル同士が一つのエリアとなります。
.wrapper{display: grid; width: 100%; height: 100%; grid-template-columns: 150px3fr 1fr; grid-template-rows: auto1fr auto; grid-template-areas: "header header header""left content right""footer footer footer"; padding: 10px; }
配置するときは、grid-area
プロパティにエリア名を指定するだけ。
.header{ grid-area: header; }.left{ grid-area: left; }.content{overflow: auto; grid-area: content; }.right{ grid-area: right; }.footer{ grid-area: footer; }
レイアウト結果は同じなので、htmlのソースとキャプチャ画像は省略します。
こうしてみると、「ココの領域は開始位置がcolumn1で、spanは・・・」などと考えずに、直感的にレイアウトできると思います。
この発想はなかった。。。なるほどなぁ、って感じの仕様です。
メディアクエリを併用しレスポンシブなレイアウト
メディアクエリと組み合わせることで、レスポンシブなレイアウト切替も簡単に実現できます。 先ほどの例と同じレイアウトですが、ウィンドウサイズをリサイズして幅を550px以下にすると、縦に一列に並んだスマホ向けっぽいレイアウトになります。
.wrapper{display: grid; width: 100%; height: 100%; grid-template-columns: auto; grid-template-rows: auto; padding: 10px; }.box{background-color: #444; color: #fff; border-radius: 5px; border: 2pxsolidblack; padding: 20px; }@media (min-width: 550px) { .wrapper { grid-template-columns: 200px3fr 1fr; grid-template-rows: auto minmax(min-content, 1fr) auto; grid-template-areas: "header header header""left content right""footer footer footer"; }.header{ grid-area: header; }.left{ grid-area: left; }.content{ grid-area: content; }.right{ grid-area: right; }.footer{ grid-area: footer; }}
サンプル
今回の全サンプルをまとめたプロジェクトを↓に置いておきました。
sourcechord/electron-gridlayout-sample · GitHub
メニューから項目を選ぶことで、ページ表示が切り替わります。
また、メニューから選択 or 「Ctrl+Shift+I」のショートカットキーでDev Toolsが出てきます。
Dev Toolsの各種パネルで色々と動きを確認することができるかと思います。
まとめ
以上、駆け足でしたが、CSS Grid Layout Module Level1を使ってElectronのアプリのレイアウトをしてみました。
実際に動かしてみると、こんなシンプルな記述で思い通りにレイアウトできる、CSS Grid Layout Moduleの威力を実感できるかと思います。
この機能をブラウザ上で気軽に使えるようになるのは、まだまだ遠い未来かもしれません。
しかし、Electronを使った開発であれば、そんな未来の世界を少し先取りして体験することができます。
あとは、この機能が気兼ねなくブラウザでも利用できるようになる日が早く来ることを願うばかりです。
明日はsoedaさんです。
よろしくお願いします♪